0
0
Fork 0

perf: customerSummaryTable

This commit is contained in:
Javier Segarra 2024-08-27 07:00:28 +02:00
parent 9a48cb0742
commit 10747d7a4f
6 changed files with 139 additions and 213 deletions

View File

@ -65,6 +65,10 @@ const $props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
disableInfiniteScroll: {
type: Boolean,
default: false,
},
hasSubToolbar: { hasSubToolbar: {
type: Boolean, type: Boolean,
default: true, default: true,
@ -335,11 +339,13 @@ defineExpose({
<div class="q-px-md"> <div class="q-px-md">
<CrudModel <CrudModel
v-bind="$attrs" v-bind="$attrs"
:limit="20" :limit="$attrs['limit'] ?? 20"
ref="CrudModelRef" ref="CrudModelRef"
@on-fetch="(...args) => emit('onFetch', ...args)" @on-fetch="(...args) => emit('onFetch', ...args)"
:search-url="searchUrl" :search-url="searchUrl"
:disable-infinite-scroll="isTableMode" :disable-infinite-scroll="
$attrs['disableInfiniteScroll'] ? isTableMode : disableInfiniteScroll
"
@save-changes="reload" @save-changes="reload"
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable" :has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
:auto-load="hasParams || $attrs['auto-load']" :auto-load="hasParams || $attrs['auto-load']"
@ -486,11 +492,7 @@ defineExpose({
:icon="btn.icon" :icon="btn.icon"
class="q-px-sm" class="q-px-sm"
flat flat
:class=" :class="'text-primary-light'"
btn.isPrimary
? 'text-primary-light'
: 'color-vn-text '
"
:style="`visibility: ${ :style="`visibility: ${
(btn.show && btn.show(row)) ?? true (btn.show && btn.show(row)) ?? true
? 'visible' ? 'visible'

View File

@ -375,6 +375,7 @@ customer:
averageInvoiced: Average invoiced averageInvoiced: Average invoiced
claimRate: Claming rate claimRate: Claming rate
risk: Risk risk: Risk
maximumRisk: Solunion's maximum risk
riskInfo: Invoices minus payments plus orders not yet invoiced riskInfo: Invoices minus payments plus orders not yet invoiced
credit: Credit credit: Credit
creditInfo: Company's maximum risk creditInfo: Company's maximum risk

View File

@ -373,6 +373,8 @@ customer:
priceIncreasingRate: Ratio de incremento de precio priceIncreasingRate: Ratio de incremento de precio
averageInvoiced: Facturación media averageInvoiced: Facturación media
claimRate: Ratio de reclamaciones claimRate: Ratio de reclamaciones
maximumRisk: Riesgo máximo asumido por Solunion
risk: Riesgo risk: Riesgo
riskInfo: Facturas menos recibos mas pedidos sin facturar riskInfo: Facturas menos recibos mas pedidos sin facturar
credit: Crédito credit: Crédito

View File

@ -2,6 +2,8 @@
import { computed, ref, onMounted } from 'vue'; import { computed, ref, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import { toCurrency, toPercentage, toDate } from 'src/filters'; import { toCurrency, toPercentage, toDate } from 'src/filters';
import CardSummary from 'components/ui/CardSummary.vue'; import CardSummary from 'components/ui/CardSummary.vue';
import { getUrl } from 'src/composables/getUrl'; import { getUrl } from 'src/composables/getUrl';
@ -40,11 +42,11 @@ const balanceDue = computed(() => {
const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : '')); const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : ''));
const claimRate = computed(() => { const claimRate = computed(() => {
return customer.value.claimsRatio.claimingRate; return customer.value.claimsRatio?.claimingRate ?? 0;
}); });
const priceIncreasingRate = computed(() => { const priceIncreasingRate = computed(() => {
return customer.value.claimsRatio.priceIncreasing / 100; return customer.value.claimsRatio?.priceIncreasing ?? 0 / 100;
}); });
const debtWarning = computed(() => { const debtWarning = computed(() => {
@ -91,7 +93,13 @@ const creditWarning = computed(() => {
<VnLv <VnLv
:label="t('customer.summary.salesPerson')" :label="t('customer.summary.salesPerson')"
:value="entity?.salesPersonUser?.name" :value="entity?.salesPersonUser?.name"
/> >
<template #value>
<VnUserLink
:name="entity.salesPersonUser?.name"
:worker-id="entity.salesPersonFk"
/> </template
></VnLv>
<VnLv <VnLv
:label="t('customer.summary.contactChannel')" :label="t('customer.summary.contactChannel')"
:value="entity?.contactChannel?.name" :value="entity?.contactChannel?.name"
@ -131,7 +139,7 @@ const creditWarning = computed(() => {
:url="`#/customer/${entityId}/fiscal-data`" :url="`#/customer/${entityId}/fiscal-data`"
:text="t('customer.summary.fiscalData')" :text="t('customer.summary.fiscalData')"
/> />
<VnRow> <VnRow class="block">
<VnLv <VnLv
:label="t('customer.summary.isEqualizated')" :label="t('customer.summary.isEqualizated')"
:value="entity.isEqualizated" :value="entity.isEqualizated"
@ -140,8 +148,8 @@ const creditWarning = computed(() => {
:label="t('customer.summary.isActive')" :label="t('customer.summary.isActive')"
:value="entity.isActive" :value="entity.isActive"
/> />
</VnRow> <!-- </VnRow>
<VnRow> <VnRow> -->
<VnLv <VnLv
:label="t('customer.summary.verifiedData')" :label="t('customer.summary.verifiedData')"
:value="entity.isTaxDataChecked" :value="entity.isTaxDataChecked"
@ -150,8 +158,8 @@ const creditWarning = computed(() => {
:label="t('customer.summary.hasToInvoice')" :label="t('customer.summary.hasToInvoice')"
:value="entity.hasToInvoice" :value="entity.hasToInvoice"
/> />
</VnRow> <!-- </VnRow>
<VnRow> <VnRow> -->
<VnLv <VnLv
:label="t('customer.summary.notifyByEmail')" :label="t('customer.summary.notifyByEmail')"
:value="entity.isToBeMailed" :value="entity.isToBeMailed"
@ -170,7 +178,7 @@ const creditWarning = computed(() => {
/> />
<VnLv :label="t('customer.summary.bankAccount')" :value="entity.iban" /> <VnLv :label="t('customer.summary.bankAccount')" :value="entity.iban" />
<VnLv :label="t('customer.summary.dueDay')" :value="entity.dueDay" /> <VnLv :label="t('customer.summary.dueDay')" :value="entity.dueDay" />
<VnRow class="q-mt-sm" wrap> <VnRow class="q-mt-sm block">
<VnLv :label="t('customer.summary.hasLcr')" :value="entity.hasLcr" /> <VnLv :label="t('customer.summary.hasLcr')" :value="entity.hasLcr" />
<VnLv <VnLv
:label="t('customer.summary.hasCoreVnl')" :label="t('customer.summary.hasCoreVnl')"
@ -227,7 +235,6 @@ const creditWarning = computed(() => {
:value="toCurrency(entity?.mana?.mana)" :value="toCurrency(entity?.mana?.mana)"
/> />
<VnLv <VnLv
v-if="entity.claimsRatio"
:label="t('customer.summary.priceIncreasingRate')" :label="t('customer.summary.priceIncreasingRate')"
:value="toPercentage(priceIncreasingRate)" :value="toPercentage(priceIncreasingRate)"
/> />
@ -236,7 +243,6 @@ const creditWarning = computed(() => {
:value="toCurrency(entity?.averageInvoiced?.invoiced)" :value="toCurrency(entity?.averageInvoiced?.invoiced)"
/> />
<VnLv <VnLv
v-if="entity.claimsRatio"
:label="t('customer.summary.claimRate')" :label="t('customer.summary.claimRate')"
:value="toPercentage(claimRate)" :value="toPercentage(claimRate)"
/> />
@ -262,12 +268,10 @@ const creditWarning = computed(() => {
/> />
<VnLv <VnLv
v-if="entity.creditInsurance"
:label="t('customer.summary.securedCredit')" :label="t('customer.summary.securedCredit')"
:value="toCurrency(entity.creditInsurance)" :value="toCurrency(entity.creditInsurance)"
:info="t('customer.summary.securedCreditInfo')" :info="t('customer.summary.securedCreditInfo')"
/> />
<VnLv <VnLv
:label="t('customer.summary.balance')" :label="t('customer.summary.balance')"
:value="toCurrency(entity.sumRisk) || toCurrency(0)" :value="toCurrency(entity.sumRisk) || toCurrency(0)"
@ -297,7 +301,7 @@ const creditWarning = computed(() => {
:value="entity.recommendedCredit" :value="entity.recommendedCredit"
/> />
</QCard> </QCard>
<QCard class="vn-one"> <QCard>
<VnTitle :text="t('Latest tickets')" /> <VnTitle :text="t('Latest tickets')" />
<CustomerSummaryTable /> <CustomerSummaryTable />
</QCard> </QCard>

View File

@ -1,22 +1,25 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { QBtn, date } from 'quasar'; import { date } from 'quasar';
import { toDateFormat } from 'src/filters/date.js';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
import FetchData from 'components/FetchData.vue'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import CustomerSummaryTableActions from './CustomerSummaryTableActions.vue'; import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import InvoiceOutDescriptorProxy from 'pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
// import FetchData from 'components/FetchData.vue';
import RouteDescriptorProxy from 'src/pages/Route/Card/RouteDescriptorProxy.vue'; import RouteDescriptorProxy from 'src/pages/Route/Card/RouteDescriptorProxy.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { viewSummary } = useSummaryDialog();
const rows = ref([]);
const filter = { const filter = {
include: [ include: [
@ -32,57 +35,6 @@ const filter = {
], ],
where: { clientFk: route.params.id }, where: { clientFk: route.params.id },
order: ['shipped DESC', 'id'], order: ['shipped DESC', 'id'],
limit: 10,
};
const tableColumnComponents = {
id: {
component: 'span',
props: () => {},
event: () => {},
},
nickname: {
component: QBtn,
props: () => ({ flat: true, color: 'blue', noCaps: true }),
event: () => {},
},
agency: {
component: 'span',
props: () => {},
event: () => {},
},
route: {
component: QBtn,
props: () => ({ flat: true, color: 'blue' }),
event: () => {},
},
packages: {
component: 'span',
props: () => {},
event: () => {},
},
date: {
component: 'span',
props: () => {},
event: () => {},
},
state: {
component: 'span',
props: () => {},
event: () => {},
},
total: {
component: 'span',
props: () => {},
event: () => {},
},
actions: {
component: CustomerSummaryTableActions,
props: (prop) => ({
id: prop.row.id,
}),
event: () => {},
},
}; };
const columns = computed(() => [ const columns = computed(() => [
@ -94,21 +46,18 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
field: 'nickname',
label: t('Nickname'), label: t('Nickname'),
name: 'nickname', name: 'nickname',
}, },
{ {
align: 'left', align: 'left',
field: (row) => row?.agencyMode?.name, format: (row) => row.agencyMode.name,
label: t('Agency'), label: t('Agency'),
name: 'agency',
}, },
{ {
align: 'left', align: 'left',
field: 'routeFk', name: 'routeFk',
label: t('Route'), label: t('Route'),
name: 'route',
}, },
{ {
align: 'left', align: 'left',
@ -118,13 +67,12 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
field: (row) => date.formatDate(row?.shipped, 'DD/MM/YYYY'), format: ({ shipped }) => date.formatDate(shipped, 'DD/MM/YYYY'),
label: t('Date'), label: t('Date'),
name: 'date', name: 'shipped',
}, },
{ {
align: 'left', align: 'left',
field: (row) => row?.ticketState?.state?.name,
label: t('State'), label: t('State'),
name: 'state', name: 'state',
}, },
@ -134,11 +82,26 @@ const columns = computed(() => [
label: t('Total'), label: t('Total'),
name: 'total', name: 'total',
}, },
{ {
align: 'left', align: 'right',
field: 'totalWithVat',
label: '', label: '',
name: 'actions', name: 'tableActions',
actions: [
{
title: t('Client ticket list'),
icon: 'vn:lines',
action: ({ id }) =>
router.push({ params: { id }, name: 'TicketSummary' }),
isPrimary: true,
},
{
title: t('Client ticket list'),
icon: 'preview',
isPrimary: true,
action: (row) => viewSummary(row.id, TicketSummary),
},
],
}, },
]); ]);
@ -156,83 +119,89 @@ const setTotalPriceColor = (ticket) => {
if (total > 0 && total < 50) return 'warning'; if (total > 0 && total < 50) return 'warning';
}; };
const navigateToticketSummary = (id) => { const setShippedColor = (date) => {
router.push({ const today = Date.vnNew();
name: 'TicketSummary', today.setHours(0, 0, 0, 0);
params: { id },
}); const ticketShipped = new Date(date);
ticketShipped.setHours(0, 0, 0, 0);
const difference = today - ticketShipped;
if (difference == 0) return 'warning';
if (difference < 0) return 'success';
}; };
const commonColumns = (col) =>
['date', 'state', 'total', 'route', 'nickname'].includes(col);
</script> </script>
<template> <template>
<FetchData <VnTable
data-key="CustomerTickets"
:filter="filter" :filter="filter"
@on-fetch="(data) => (rows = data)"
auto-load
url="Tickets" url="Tickets"
/> :columns="columns"
<QCard class="vn-one q-py-sm flex justify-between"> search-url="tickets"
<QTable :without-header="true"
:columns="columns" auto-load
:pagination="{ rowsPerPage: 12 }" order="shipped DESC, id"
:rows="rows" limit="5"
class="full-width" >
row-key="id" <template #column-nickname="{ row }">
> <span class="link">
<template #body-cell="props"> {{ row.nickname }}
<QTd :props="props" @click="navigateToticketSummary(props.row.id)"> <TicketDescriptorProxy :id="row.nickname" />
<QTr :props="props" class="cursor-pointer"> </span>
<component </template>
:is="tableColumnComponents[props.col.name].component" <template #column-ticketFk="{ row }">
@click="tableColumnComponents[props.col.name].event(props)" <span class="link">
class="rounded-borders" {{ row.ticketFk }}
v-bind="tableColumnComponents[props.col.name].props(props)" <TicketDescriptorProxy :id="row.ticketFk" />
> </span>
<template v-if="!commonColumns(props.col.name)"> </template>
<span>
{{ props.value }} <template #column-routeFk="{ row }">
</span> <span class="link">
</template> {{ row.routeFk }}
<template v-if="props.col.name === 'route'"> <RouteDescriptorProxy :id="row.ticketFk" />
<span class="link" @click.stop> </span>
<RouteDescriptorProxy :id="props.row.routeFk" /> </template>
{{ props.value }} <template #column-total="{ row }">
</span> <QBadge
</template> class="q-pa-sm"
<template v-if="props.col.name === 'nickname'"> v-if="setTotalPriceColor(row)"
<span class="link" @click.stop> :color="setTotalPriceColor(row)"
<CustomerDescriptorProxy :id="props.row.clientFk" /> >
{{ props.value }} <!-- {{ setTotalPriceColor(row) }} -->
</span> {{ toCurrency(row.totalWithVat) }}
</template> </QBadge>
<template v-if="props.col.name === 'date'"> <span v-else> {{ toCurrency(row.totalWithVat) }}</span>
<QBadge class="q-pa-sm" color="warning"> </template>
{{ props.value }} <template #column-state="{ row }">
</QBadge> <span v-if="row.invoiceOut">
</template> <span :class="{ link: row.invoiceOut.ref }">
<template v-if="props.col.name === 'state'"> {{ row.invoiceOut.ref }}
<QBadge :color="setStateColor(props.row)" class="q-pa-sm"> <InvoiceOutDescriptorProxy :id="row.invoiceOut.id" />
{{ props.value }} </span>
</QBadge> </span>
</template> <QBadge
<template v-if="props.col.name === 'total'"> class="q-pa-sm"
<QBadge :color="setStateColor(row)"
:color="setTotalPriceColor(props.row)" v-else-if="setStateColor(row)"
class="q-pa-sm" >
v-if="setTotalPriceColor(props.row)" {{ row?.ticketState?.state.name }}
> </QBadge>
{{ toCurrency(props.value) }} <span v-else> {{ row?.ticketState?.state.name }}</span>
</QBadge> </template>
<div v-else>{{ toCurrency(props.value) }}</div> <template #column-shipped="{ row }">
</template> <QBadge
</component> class="q-pa-sm"
</QTr> :color="setShippedColor(row.shipped)"
</QTd> v-if="setShippedColor(row.shipped)"
</template> >
</QTable> {{ toDateFormat(row.shipped) }}
</QCard> </QBadge>
<span v-else> {{ toDateFormat(row.shipped) }}</span>
</template>
</VnTable>
</template> </template>
<i18n> <i18n>

View File

@ -1,52 +0,0 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
const { t } = useI18n();
const router = useRouter();
defineProps({
id: {
type: Number,
required: true,
},
});
const { viewSummary } = useSummaryDialog();
</script>
<template>
<div>
{{ id }}
<QIcon
color="primary"
name="vn:lines"
size="sm"
@click.stop="router.push({ params: { id }, name: 'TicketSale' })"
>
<QTooltip>
{{ t('Go to lines') }}
</QTooltip>
</QIcon>
<QIcon
@click.stop="viewSummary(id, TicketSummary)"
class="q-ml-md"
color="primary"
name="preview"
size="sm"
>
<QTooltip>
{{ t('Preview') }}
</QTooltip>
</QIcon>
</div>
</template>
<i18n>
es:
Go to lines: Ir a lineas
Preview: Vista previa
</i18n>