Summary refactor
gitea/salix-front/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2023-01-30 15:32:44 +01:00
parent c95759f302
commit 5809e36ddb
11 changed files with 936 additions and 807 deletions

View File

@ -1,44 +1,40 @@
<script setup> <script setup>
import { onMounted, useSlots, computed, ref, toRef, watch } from 'vue'; import { onMounted, useSlots, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue'; import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
const props = defineProps({ const props = defineProps({
id: { url: {
type: Number, type: String,
required: true, default: '',
},
filter: {
type: Object,
default: null,
}, },
module: { module: {
type: String, type: String,
required: true, required: true,
}, }
description: {
type: String,
required: false,
default: '',
},
}); });
const slots = useSlots(); const slots = useSlots();
const { t } = useI18n(); const { t } = useI18n();
onMounted(async () => { onMounted(() => fetch());
await fetch();
});
const entity = ref(); const entity = ref();
const entityId = toRef(props, 'id');
const description = computed(() => {
return props.description || entity.value.name;
});
async function fetch() { async function fetch() {
const { data } = await axios.get(`Clients/${entityId.value}/getCard`); const params = {};
if (props.filter) params.filter = props.filter;
const { data } = await axios.get(props.url, { params });
entity.value = data; entity.value = data;
} }
watch(entityId, async () => { watch(props, async () => {
entity.value = null; entity.value = null;
await fetch(); await fetch();
}); });
@ -46,40 +42,63 @@ watch(entityId, async () => {
<template> <template>
<div class="descriptor"> <div class="descriptor">
<div class="header bg-primary q-pa-sm"> <template v-if="entity">
<router-link :to="{ name: `${module}List` }"> <div class="header bg-primary q-pa-sm">
<q-btn round flat dense size="md" icon="view_list" color="white"> <router-link :to="{ name: `${module}List` }">
<q-tooltip>{{ t('components.cardDescriptor.mainList') }}</q-tooltip> <q-btn round flat dense size="md" icon="view_list" color="white">
</q-btn> <q-tooltip>{{
</router-link> t('components.cardDescriptor.mainList')
<router-link :to="{ name: `${module}Summary`, params: { id: entityId } }"> }}</q-tooltip>
<q-btn round flat dense size="md" icon="launch" color="white"> </q-btn>
<q-tooltip>{{ t('components.cardDescriptor.summary') }}</q-tooltip> </router-link>
</q-btn> <router-link
</router-link> :to="{ name: `${module}Summary`, params: { id: entity.id } }"
>
<q-btn v-if="slots.menu" size="md" icon="more_vert" color="white" round flat dense> <q-btn round flat dense size="md" icon="launch" color="white">
<q-tooltip>{{ t('components.cardDescriptor.moreOptions') }}</q-tooltip> <q-tooltip>{{
<q-menu> t('components.cardDescriptor.summary')
<q-list> }}</q-tooltip>
<slot name="menu" /> </q-btn>
</q-list> </router-link>
</q-menu>
</q-btn>
</div>
<div v-if="entity" class="body q-py-sm">
<q-list>
<q-item-label header class="ellipsis text-h5" :lines="1">
{{ description }}
<q-tooltip>{{ description }}</q-tooltip>
</q-item-label>
<q-item dense>
<q-item-label class="text-subtitle2" caption>#{{ entity.id }}</q-item-label>
</q-item>
</q-list>
<slot name="body" :entity="entity" />
</div>
<q-btn
v-if="slots.menu"
size="md"
icon="more_vert"
color="white"
round
flat
dense
>
<q-tooltip>
{{ t('components.cardDescriptor.moreOptions') }}
</q-tooltip>
<q-menu>
<q-list>
<slot name="menu" :entity="entity" />
</q-list>
</q-menu>
</q-btn>
</div>
<div class="body q-py-sm">
<q-list>
<q-item-label header class="ellipsis text-h5" :lines="1">
<slot name="description" :entity="entity">
<span>
{{ entity.name }}
<q-tooltip>{{ entity.name }}</q-tooltip>
</span>
</slot>
</q-item-label>
<q-item dense>
<q-item-label class="text-subtitle2" caption>
#{{ entity.id }}
</q-item-label>
</q-item>
</q-list>
<slot name="body" :entity="entity" />
</div>
</template>
<!-- Skeleton --> <!-- Skeleton -->
<skeleton-descriptor v-if="!entity" /> <skeleton-descriptor v-if="!entity" />
</div> </div>

View File

@ -1,19 +1,21 @@
<script setup> <script setup>
import { onMounted, toRef, ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
import axios from 'axios'; import axios from 'axios';
import SkeletonSummary from 'components/ui/SkeletonSummary.vue'; import SkeletonSummary from 'components/ui/SkeletonSummary.vue';
const props = defineProps({
id: {
type: Number,
required: true,
},
});
onMounted(() => fetch()); onMounted(() => fetch());
const entity = ref(); const entity = ref();
const entityId = toRef(props, 'id'); const props = defineProps({
url: {
type: String,
default: '',
},
filter: {
type: Object,
default: null,
},
});
const emit = defineEmits(['onFetch']);
defineExpose({ defineExpose({
entity, entity,
@ -21,12 +23,17 @@ defineExpose({
}); });
async function fetch() { async function fetch() {
const id = entityId.value; const params = {};
const { data } = await axios.get(`Clients/${id}/summary`);
if (props.filter) params.filter = props.filter;
const { data } = await axios.get(props.url, { params });
entity.value = data; entity.value = data;
emit('onFetch', data);
} }
watch(entityId, async () => { watch(props, async () => {
entity.value = null; entity.value = null;
fetch(); fetch();
}); });
@ -38,9 +45,11 @@ watch(entityId, async () => {
<skeleton-summary v-if="!entity" /> <skeleton-summary v-if="!entity" />
<template v-if="entity"> <template v-if="entity">
<div class="header bg-primary q-pa-sm q-mb-md"> <div class="header bg-primary q-pa-sm q-mb-md">
<slot name="header" :entity="entity"> {{ entity.id }} - {{ entity.name }} </slot> <slot name="header" :entity="entity">
{{ entity.id }} - {{ entity.name }}
</slot>
</div> </div>
<div class="row q-pa-md q-col-gutter-md q-mb-md"> <div class="body q-pa-md q-mb-md">
<slot name="body" :entity="entity" /> <slot name="body" :entity="entity" />
</div> </div>
</template> </template>
@ -73,10 +82,11 @@ watch(entityId, async () => {
} }
} }
} }
.row {
.body > .q-card__section.row {
flex-wrap: wrap; flex-wrap: wrap;
.col { & > .col {
min-width: 250px; min-width: 250px;
} }
} }

View File

@ -28,7 +28,7 @@ $color-spacer: rgba(255, 255, 255, 0.3);
$border-thin-light: 1px solid $color-spacer-light; $border-thin-light: 1px solid $color-spacer-light;
$dark-shadow-color: #000; $dark-shadow-color: #000;
$dark: #3c3b3b; $dark: #292929;
$layout-shadow-dark: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0px 10px rgba(0, 0, 0, 0.24); $layout-shadow-dark: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0px 10px rgba(0, 0, 0, 0.24);
$spacing-md: 16px; $spacing-md: 16px;

View File

@ -20,7 +20,7 @@ const state = useState();
</q-page-container> </q-page-container>
</template> </template>
<style lang="scss"> <!-- <style lang="scss">
.q-scrollarea__content { .q-scrollarea__content {
max-width: 100%; max-width: 100%;
} }
@ -47,4 +47,4 @@ const state = useState();
justify-content: space-between; justify-content: space-between;
} }
} }
</style> </style> -->

View File

@ -1,13 +1,12 @@
<script setup> <script setup>
import { onMounted, computed, ref } from 'vue'; import { computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
import axios from 'axios';
import TicketDescriptorPopover from 'pages/Ticket/Card/TicketDescriptorPopover.vue'; import TicketDescriptorPopover from 'pages/Ticket/Card/TicketDescriptorPopover.vue';
import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue'; import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -17,10 +16,6 @@ const $props = defineProps({
}, },
}); });
onMounted(async () => {
await fetch();
});
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
@ -28,28 +23,21 @@ const entityId = computed(() => {
return $props.id || route.params.id; return $props.id || route.params.id;
}); });
const claim = ref(); const filter = {
async function fetch() { include: [
const filter = { { relation: 'client' },
include: [ { relation: 'claimState' },
{ relation: 'client' }, {
{ relation: 'claimState' }, relation: 'claimState',
{ },
relation: 'claimState', {
relation: 'worker',
scope: {
include: { relation: 'user' },
}, },
{ },
relation: 'worker', ],
scope: { };
include: { relation: 'user' },
},
},
],
};
const options = { params: { filter } };
const { data } = await axios.get(`Claims/${entityId.value}`, options);
if (data) claim.value = data;
}
function stateColor(code) { function stateColor(code) {
if (code === 'pending') return 'green'; if (code === 'pending') return 'green';
@ -59,40 +47,56 @@ function stateColor(code) {
</script> </script>
<template> <template>
<skeleton-descriptor v-if="!claim" /> <card-descriptor
<card-descriptor v-if="claim" module="Claim" :data="claim" :description="claim.client.name"> ref="descriptor"
<template #menu> :url="`Claims/${entityId}`"
<claim-descriptor-menu v-if="claim" :claim="claim" /> :filter="filter"
module="Claim"
>
<template #menu="{ entity }">
<claim-descriptor-menu :claim="entity" />
</template> </template>
<template #body> <template #description="{ entity }">
<span>
{{ entity.client.name }}
<q-tooltip>{{ entity.client.name }}</q-tooltip>
</span>
</template>
<template #body="{ entity }">
<q-list> <q-list>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('claim.card.created') }}</q-item-label> <q-item-label caption>{{ t('claim.card.created') }}</q-item-label>
<q-item-label>{{ toDate(claim.created) }}</q-item-label> <q-item-label>{{ toDate(entity.created) }}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section v-if="entity.claimState">
<q-item-label caption>{{ t('claim.card.state') }}</q-item-label> <q-item-label caption>{{ t('claim.card.state') }}</q-item-label>
<q-item-label> <q-item-label>
<q-chip :color="stateColor(claim.claimState.code)" dense> <q-chip :color="stateColor(entity.claimState.code)" dense>
{{ claim.claimState.description }} {{ entity.claimState.description }}
</q-chip> </q-chip>
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('claim.card.ticketId') }}</q-item-label> <q-item-label caption>
<q-item-label class="link"> {{ t('claim.card.ticketId') }}
{{ claim.ticketFk }} </q-item-label>
<q-popup-proxy> <q-item-label>
<ticket-descriptor-popover :id="claim.ticketFk" /> <span class="link">
</q-popup-proxy> {{ entity.ticketFk }}
<q-popup-proxy>
<ticket-descriptor-popover :id="entity.ticketFk" />
</q-popup-proxy>
</span>
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section v-if="entity.worker">
<q-item-label caption>{{ t('claim.card.assignedTo') }}</q-item-label> <q-item-label caption>
<q-item-label>{{ claim.worker.user.name }}</q-item-label> {{ t('claim.card.assignedTo') }}
</q-item-label>
<q-item-label>{{ entity.worker.user.name }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
@ -102,7 +106,7 @@ function stateColor(code) {
size="md" size="md"
icon="vn:client" icon="vn:client"
color="primary" color="primary"
:to="{ name: 'CustomerCard', params: { id: claim.clientFk } }" :to="{ name: 'CustomerCard', params: { id: entity.clientFk } }"
> >
<q-tooltip>{{ t('claim.card.customerSummary') }}</q-tooltip> <q-tooltip>{{ t('claim.card.customerSummary') }}</q-tooltip>
</q-btn> </q-btn>
@ -110,7 +114,7 @@ function stateColor(code) {
size="md" size="md"
icon="vn:ticket" icon="vn:ticket"
color="primary" color="primary"
:to="{ name: 'TicketCard', params: { id: claim.ticketFk } }" :to="{ name: 'TicketCard', params: { id: entity.ticketFk } }"
> >
<q-tooltip>{{ t('claim.card.claimedTicket') }}</q-tooltip> <q-tooltip>{{ t('claim.card.claimedTicket') }}</q-tooltip>
</q-btn> </q-btn>

View File

@ -1,12 +1,9 @@
<script setup> <script setup>
import { onMounted, ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios';
import { toDate, toCurrency } from 'src/filters'; import { toDate, toCurrency } from 'src/filters';
import SkeletonSummary from 'components/ui/SkeletonSummary.vue'; import CardSummary from 'components/ui/CardSummary.vue';
onMounted(() => fetch());
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
@ -20,16 +17,6 @@ const $props = defineProps({
const entityId = computed(() => $props.id || route.params.id); const entityId = computed(() => $props.id || route.params.id);
const claim = ref(null);
const salesClaimed = ref(null);
function fetch() {
const id = entityId.value;
axios.get(`Claims/${id}/getSummary`).then(({ data }) => {
claim.value = data.claim;
salesClaimed.value = data.salesClaimed;
});
}
const detailsColumns = ref([ const detailsColumns = ref([
{ {
name: 'item', name: 'item',
@ -77,7 +64,8 @@ const detailsColumns = ref([
{ {
name: 'total', name: 'total',
label: 'claim.summary.total', label: 'claim.summary.total',
field: ({ sale }) => toCurrency(sale.quantity * sale.price * ((100 - sale.discount) / 100)), field: ({ sale }) =>
toCurrency(sale.quantity * sale.price * ((100 - sale.discount) / 100)),
sortable: true, sortable: true,
}, },
]); ]);
@ -90,110 +78,129 @@ function stateColor(code) {
</script> </script>
<template> <template>
<div class="summary container"> <card-summary ref="summary" :url="`Claims/${entityId}/getSummary`">
<q-card> <template #header="{ entity: { claim } }">
<skeleton-summary v-if="!claim" /> {{ claim.id }} - {{ claim.client.name }}
<template v-if="claim"> </template>
<div class="header bg-primary q-pa-sm q-mb-md">{{ claim.id }} - {{ claim.client.name }}</div> <template #body="{ entity: { claim, salesClaimed } }">
<q-list> <q-card-section class="row q-pa-none q-col-gutter-md">
<q-item> <div class="col">
<q-item-section> <q-list>
<q-item-label caption>{{ t('claim.summary.created') }}</q-item-label> <q-item>
<q-item-label>{{ toDate(claim.created) }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
<q-item-section> {{ t('claim.summary.created') }}
<q-item-label caption>{{ t('claim.summary.state') }}</q-item-label> </q-item-label>
<q-item-label> <q-item-label>{{ toDate(claim.created) }}</q-item-label>
<q-chip :color="stateColor(claim.claimState.code)" dense> </q-item-section>
{{ claim.claimState.description }} <q-item-section v-if="claim.claimState">
</q-chip> <q-item-label caption>{{
</q-item-label> t('claim.summary.state')
</q-item-section> }}</q-item-label>
</q-item> <q-item-label>
<q-item> <q-chip
<q-item-section> :color="stateColor(claim.claimState.code)"
<q-item-label caption>{{ t('claim.summary.assignedTo') }}</q-item-label> dense
<q-item-label>{{ claim.worker.user.nickname }}</q-item-label> >
</q-item-section> {{ claim.claimState.description }}
<q-item-section> </q-chip>
<q-item-label caption>{{ t('claim.summary.attendedBy') }}</q-item-label> </q-item-label>
<q-item-label>{{ claim.client.salesPersonUser.name }}</q-item-label> </q-item-section>
</q-item-section> </q-item>
</q-item> <q-item>
</q-list> <q-item-section v-if="claim.worker && claim.worker.user">
<q-card-section class="q-pa-md"> <q-item-label caption>{{
<h6>{{ t('claim.summary.details') }}</h6> t('claim.summary.assignedTo')
<q-table :columns="detailsColumns" :rows="salesClaimed" flat> }}</q-item-label>
<template #header="props"> <q-item-label>{{
<q-tr :props="props"> claim.worker.user.nickname
<q-th v-for="col in props.cols" :key="col.name" :props="props"> }}</q-item-label>
{{ t(col.label) }} </q-item-section>
</q-th> <q-item-section
</q-tr> v-if="claim.client && claim.client.salesPersonUser"
</template> >
</q-table> <q-item-label caption>{{
</q-card-section> t('claim.summary.attendedBy')
<q-card-section class="q-pa-md"> }}</q-item-label>
<h6>{{ t('claim.summary.actions') }}</h6> <q-item-label>{{
<q-separator /> claim.client.salesPersonUser.name
<div id="slider-container"> }}</q-item-label>
<q-slider </q-item-section>
v-model="claim.responsibility" </q-item>
label </q-list>
:label-value="t('claim.summary.responsibility')" </div>
label-always </q-card-section>
color="primary" <q-card-section class="q-pa-md">
markers <h6>{{ t('claim.summary.details') }}</h6>
:marker-labels="[ <q-table :columns="detailsColumns" :rows="salesClaimed" flat>
{ value: 1, label: t('claim.summary.company') }, <template #header="props">
{ value: 5, label: t('claim.summary.person') }, <q-tr :props="props">
]" <q-th
:min="1" v-for="col in props.cols"
:max="5" :key="col.name"
readonly :props="props"
/> >
</div> {{ t(col.label) }}
</q-card-section> </q-th>
</template> </q-tr>
</q-card> </template>
</div> </q-table>
</q-card-section>
<q-card-section class="q-pa-md">
<h6>{{ t('claim.summary.actions') }}</h6>
<q-separator />
<div id="slider-container">
<q-slider
v-model="claim.responsibility"
label
:label-value="t('claim.summary.responsibility')"
label-always
color="primary"
markers
:marker-labels="[
{ value: 1, label: t('claim.summary.company') },
{ value: 5, label: t('claim.summary.person') },
]"
:min="1"
:max="5"
readonly
/>
</div>
</q-card-section>
</template>
</card-summary>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.container { // .container {
display: flex; // display: flex;
justify-content: center; // justify-content: center;
} // }
.q-card { // .q-card {
width: 100%; // width: 100%;
max-width: 950px; // max-width: 950px;
} // }
.summary { // .summary {
.header { // #slider-container {
text-align: center; // max-width: 80%;
font-size: 18px; // margin: 0 auto;
}
#slider-container { // .q-slider {
max-width: 80%; // .q-slider__marker-labels:nth-child(1) {
margin: 0 auto; // transform: none;
// }
// .q-slider__marker-labels:nth-child(2) {
// transform: none;
// left: auto !important;
// right: 0%;
// }
// }
// }
// }
.q-slider { // .q-dialog .summary {
.q-slider__marker-labels:nth-child(1) { // max-width: 1200px;
transform: none; // }
}
.q-slider__marker-labels:nth-child(2) {
transform: none;
left: auto !important;
right: 0%;
}
}
}
}
.q-dialog .summary {
max-width: 1200px;
}
</style> </style>

View File

@ -9,7 +9,7 @@ const $props = defineProps({
id: { id: {
type: Number, type: Number,
required: false, required: false,
default: 0, default: null,
}, },
}); });
@ -17,56 +17,90 @@ const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const entityId = computed(() => { const entityId = computed(() => {
return $props.id || Number(route.params.id); return $props.id || route.params.id;
}); });
</script> </script>
<template> <template>
<card-descriptor ref="descriptor" :id="entityId" module="Customer"> <card-descriptor module="Customer" :url="`Clients/${entityId}/getCard`">
<!-- <template #menu>
<q-item clickable v-ripple>Option 1</q-item>
<q-item clickable v-ripple>Option 2</q-item>
</template> -->
<template #body="{ entity }"> <template #body="{ entity }">
<q-list> <q-list>
<q-item v-if="entity.salesPersonUser"> <q-item v-if="entity.salesPersonUser">
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('customer.card.salesPerson') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ entity.salesPersonUser.name }}</q-item-label> t('customer.card.salesPerson')
}}</q-item-label>
<q-item-label>
{{ entity.salesPersonUser.name }}
</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('customer.card.credit') }}</q-item-label> <q-item-label caption>
<q-item-label>{{ toCurrency(entity.credit) }}</q-item-label> {{ t('customer.card.credit') }}
</q-item-label>
<q-item-label>
{{ toCurrency(entity.credit) }}
</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('customer.card.securedCredit') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ toCurrency(entity.creditInsurance) }}</q-item-label> t('customer.card.securedCredit')
}}</q-item-label>
<q-item-label>
{{ toCurrency(entity.creditInsurance) }}
</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section v-if="entity.payMethod"> <q-item-section v-if="entity.payMethod">
<q-item-label caption>{{ t('customer.card.payMethod') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ entity.payMethod.name }}</q-item-label> t('customer.card.payMethod')
}}</q-item-label>
<q-item-label>
{{ entity.payMethod.name }}
</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('customer.card.debt') }}</q-item-label> <q-item-label caption>{{ t('customer.card.debt') }}</q-item-label>
<q-item-label>{{ toCurrency(entity.debt) }}</q-item-label> <q-item-label>
{{ toCurrency(entity.debt) }}
</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
<q-card-actions class="q-gutter-md"> <q-card-actions class="q-gutter-md">
<q-icon v-if="entity.isActive == false" name="vn:disabled" size="xs" color="primary"> <q-icon
v-if="entity.isActive == false"
name="vn:disabled"
size="xs"
color="primary"
>
<q-tooltip>{{ t('customer.card.isDisabled') }}</q-tooltip> <q-tooltip>{{ t('customer.card.isDisabled') }}</q-tooltip>
</q-icon> </q-icon>
<q-icon v-if="entity.isFreezed == true" name="vn:frozen" size="xs" color="primary"> <q-icon
v-if="entity.isFreezed == true"
name="vn:frozen"
size="xs"
color="primary"
>
<q-tooltip>{{ t('customer.card.isFrozen') }}</q-tooltip> <q-tooltip>{{ t('customer.card.isFrozen') }}</q-tooltip>
</q-icon> </q-icon>
<q-icon v-if="entity.debt > entity.credit" name="vn:risk" size="xs" color="primary"> <q-icon
v-if="entity.debt > entity.credit"
name="vn:risk"
size="xs"
color="primary"
>
<q-tooltip>{{ t('customer.card.hasDebt') }}</q-tooltip> <q-tooltip>{{ t('customer.card.hasDebt') }}</q-tooltip>
</q-icon> </q-icon>
<q-icon v-if="entity.isTaxDataChecked == false" name="vn:no036" size="xs" color="primary"> <q-icon
v-if="entity.isTaxDataChecked == false"
name="vn:no036"
size="xs"
color="primary"
>
<q-tooltip>{{ t('customer.card.notChecked') }}</q-tooltip> <q-tooltip>{{ t('customer.card.notChecked') }}</q-tooltip>
</q-icon> </q-icon>
<q-icon <q-icon

View File

@ -15,7 +15,7 @@ const $props = defineProps({
}, },
}); });
const entityId = computed(() => Number($props.id) || Number(route.params.id)); const entityId = computed(() => $props.id || route.params.id);
const summary = ref(); const summary = ref();
const customer = computed(() => summary.value.entity); const customer = computed(() => summary.value.entity);
@ -51,463 +51,474 @@ const creditWarning = computed(() => {
</script> </script>
<template> <template>
<card-summary ref="summary" :id="entityId"> <card-summary ref="summary" :url="`Clients/${entityId}/summary`">
<template #body="{ entity }"> <template #body="{ entity }">
<div class="col"> <q-card-section class="row q-pa-none q-col-gutter-md">
<q-list> <div class="col">
<q-item-label header class="text-h6"> <q-list>
{{ t('customer.summary.basicData') }} <q-item-label header class="text-h6">
<router-link {{ t('customer.summary.basicData') }}
:to="{ name: 'CustomerBasicData', params: { id: entityId } }" <router-link
target="_blank" :to="{
> name: 'CustomerBasicData',
<q-icon name="open_in_new" /> params: { id: entity.id },
</router-link> }"
</q-item-label> target="_blank"
>
<q-icon name="open_in_new" />
</router-link>
</q-item-label>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ <q-item-label caption>
t('customer.summary.customerId') {{ t('customer.summary.customerId') }}
}}</q-item-label> </q-item-label>
<q-item-label>{{ entity.id }}</q-item-label> <q-item-label>{{ entity.id }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ <q-item-label caption>
t('customer.summary.name') {{ t('customer.summary.name') }}
}}</q-item-label> </q-item-label>
<q-item-label>{{ entity.name }}</q-item-label> <q-item-label>{{ entity.name }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ <q-item-label caption>
t('customer.summary.contact') {{ t('customer.summary.contact') }}
}}</q-item-label> </q-item-label>
<q-item-label>{{ entity.contact }}</q-item-label> <q-item-label>{{ entity.contact }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item v-if="entity.salesPersonUser"> <q-item v-if="entity.salesPersonUser">
<q-item-section> <q-item-section>
<q-item-label caption>{{ <q-item-label caption>
t('customer.summary.salesPerson') {{ t('customer.summary.salesPerson') }}
}}</q-item-label> </q-item-label>
<q-item-label>{{ entity.salesPersonUser.name }}</q-item-label> <q-item-label>{{
</q-item-section> entity.salesPersonUser.name
</q-item> }}</q-item-label>
<q-item> </q-item-section>
<q-item-section> </q-item>
<q-item-label caption>{{ <q-item>
t('customer.summary.phone') <q-item-section>
}}</q-item-label> <q-item-label caption>
<q-item-label>{{ entity.phone }}</q-item-label> {{ t('customer.summary.phone') }}
</q-item-section> </q-item-label>
</q-item> <q-item-label>{{ entity.phone }}</q-item-label>
<q-item> </q-item-section>
<q-item-section> </q-item>
<q-item-label caption>{{ <q-item>
t('customer.summary.mobile') <q-item-section>
}}</q-item-label> <q-item-label caption>
<q-item-label>{{ entity.mobile }}</q-item-label> {{ t('customer.summary.mobile') }}
</q-item-section> </q-item-label>
</q-item> <q-item-label>{{ entity.mobile }}</q-item-label>
<q-item> </q-item-section>
<q-item-section> </q-item>
<q-item-label caption>{{ <q-item>
t('customer.summary.email') <q-item-section>
}}</q-item-label> <q-item-label caption>
<q-item-label>{{ entity.email }}</q-item-label> {{ t('customer.summary.email') }}
</q-item-section> </q-item-label>
</q-item> <q-item-label>{{ entity.email }}</q-item-label>
<q-item v-if="entity.contactChannel"> </q-item-section>
<q-item-section> </q-item>
<q-item-label caption>{{ <q-item v-if="entity.contactChannel">
t('customer.summary.contactChannel') <q-item-section>
}}</q-item-label> <q-item-label caption>
<q-item-label>{{ entity.contactChannel.name }}</q-item-label> {{ t('customer.summary.contactChannel') }}
</q-item-section> </q-item-label>
</q-item> <q-item-label>{{
</q-list> entity.contactChannel.name
</div> }}</q-item-label>
<div class="col"> </q-item-section>
<q-list> </q-item>
<q-item-label header class="text-h6"> </q-list>
{{ t('customer.summary.fiscalAddress') }} </div>
</q-item-label> <div class="col">
<q-item> <q-list>
<q-item-section> <q-item-label header class="text-h6">
<q-item-label caption>{{ {{ t('customer.summary.fiscalAddress') }}
t('customer.summary.socialName') </q-item-label>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.socialName }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.socialName') }}
<q-item> </q-item-label>
<q-item-section> <q-item-label>{{ entity.socialName }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.fiscalId') </q-item>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.fi }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.fiscalId') }}
<q-item> </q-item-label>
<q-item-section> <q-item-label>{{ entity.fi }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.postcode') </q-item>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.postcode }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.postcode') }}
<q-item v-if="entity.province"> </q-item-label>
<q-item-section> <q-item-label>{{ entity.postcode }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.province') </q-item>
}}</q-item-label> <q-item v-if="entity.province">
<q-item-label>{{ entity.province.name }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.province') }}
<q-item v-if="entity.country"> </q-item-label>
<q-item-section> <q-item-label>{{ entity.province.name }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.country') </q-item>
}}</q-item-label> <q-item v-if="entity.country">
<q-item-label>{{ entity.country.country }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.country') }}
<q-item> </q-item-label>
<q-item-section> <q-item-label>{{ entity.country.country }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.street') </q-item>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.street }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.street') }}
</q-list> </q-item-label>
</div> <q-item-label>{{ entity.street }}</q-item-label>
<div class="col"> </q-item-section>
<q-list> </q-item>
<q-item-label header class="text-h6"> </q-list>
{{ t('customer.summary.fiscalData') }} </div>
</q-item-label> <div class="col">
<q-item dense> <q-list>
<q-checkbox <q-item-label header class="text-h6">
v-model="entity.isEqualizated" {{ t('customer.summary.fiscalData') }}
:label="t('customer.summary.isEqualizated')" </q-item-label>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.isEqualizated"
<q-item dense> :label="t('customer.summary.isEqualizated')"
<q-checkbox disable
v-model="entity.isActive" />
:label="t('customer.summary.isActive')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.isActive"
<q-item dense> :label="t('customer.summary.isActive')"
<q-checkbox disable
v-model="entity.hasToInvoiceByAddress" />
:label="t('customer.summary.invoiceByAddress')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.hasToInvoiceByAddress"
<q-item dense> :label="t('customer.summary.invoiceByAddress')"
<q-checkbox disable
v-model="entity.isTaxDataChecked" />
:label="t('customer.summary.verifiedData')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.isTaxDataChecked"
<q-item dense> :label="t('customer.summary.verifiedData')"
<q-checkbox disable
v-model="entity.hasToInvoice" />
:label="t('customer.summary.hasToInvoice')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.hasToInvoice"
<q-item dense> :label="t('customer.summary.hasToInvoice')"
<q-checkbox disable
v-model="entity.isToBeMailed" />
:label="t('customer.summary.notifyByEmail')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.isToBeMailed"
<q-item dense> :label="t('customer.summary.notifyByEmail')"
<q-checkbox disable
v-model="entity.isVies" />
:label="t('customer.summary.vies')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.isVies"
</q-list> :label="t('customer.summary.vies')"
</div> disable
<div class="col"> />
<q-list> </q-item>
<q-item-label header class="text-h6"> </q-list>
{{ t('customer.summary.billingData') }} </div>
</q-item-label> <div class="col">
<q-item> <q-list>
<q-item-section> <q-item-label header class="text-h6">
<q-item-label caption>{{ {{ t('customer.summary.billingData') }}
t('customer.summary.payMethod') </q-item-label>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.payMethod.name }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.payMethod') }}
<q-item> </q-item-label>
<q-item-section> <q-item-label>{{ entity.payMethod.name }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.bankAccount') </q-item>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.iban }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.bankAccount') }}
<q-item> </q-item-label>
<q-item-section> <q-item-label>{{ entity.iban }}</q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.dueDay') </q-item>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.dueDay }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.dueDay') }}
<q-item dense> </q-item-label>
<q-checkbox <q-item-label>{{ entity.dueDay }}</q-item-label>
v-model="entity.hasLcr" </q-item-section>
:label="t('customer.summary.hasLcr')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.hasLcr"
<q-item dense> :label="t('customer.summary.hasLcr')"
<q-checkbox disable
v-model="entity.hasCoreVnl" />
:label="t('customer.summary.hasCoreVnl')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.hasCoreVnl"
<q-item dense> :label="t('customer.summary.hasCoreVnl')"
<q-checkbox disable
v-model="entity.hasSepaVnl" />
:label="t('customer.summary.hasB2BVnl')" </q-item>
disable <q-item dense>
/> <q-checkbox
</q-item> v-model="entity.hasSepaVnl"
</q-list> :label="t('customer.summary.hasB2BVnl')"
</div> disable
<div class="col" v-if="entity.defaultAddress"> />
<q-list> </q-item>
<q-item-label header class="text-h6"> </q-list>
{{ t('customer.summary.consignee') }} </div>
</q-item-label> <div class="col" v-if="entity.defaultAddress">
<q-item> <q-list>
<q-item-section> <q-item-label header class="text-h6">
<q-item-label caption>{{ {{ t('customer.summary.consignee') }}
t('customer.summary.addressName') </q-item-label>
}}</q-item-label> <q-item>
<q-item-label>{{ <q-item-section>
entity.defaultAddress.nickname <q-item-label caption>
}}</q-item-label> {{ t('customer.summary.addressName') }}
</q-item-section> </q-item-label>
</q-item> <q-item-label>
<q-item> {{ entity.defaultAddress.nickname }}
<q-item-section> </q-item-label>
<q-item-label caption>{{ </q-item-section>
t('customer.summary.addressCity') </q-item>
}}</q-item-label> <q-item>
<q-item-label>{{ entity.defaultAddress.city }}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.addressCity') }}
<q-item> </q-item-label>
<q-item-section> <q-item-label>{{
<q-item-label caption>{{ entity.defaultAddress.city
t('customer.summary.addressStreet') }}</q-item-label>
}}</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
entity.defaultAddress.street <q-item>
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.addressStreet') }}
</q-list> </q-item-label>
</div> <q-item-label>
<div class="col" v-if="entity.account"> {{ entity.defaultAddress.street }}
<q-list> </q-item-label>
<q-item-label header class="text-h6"> </q-item-section>
{{ t('customer.summary.webAccess') }} </q-item>
</q-item-label> </q-list>
<q-item> </div>
<q-item-section> <div class="col" v-if="entity.account">
<q-item-label caption>{{ <q-list>
t('customer.summary.username') <q-item-label header class="text-h6">
}}</q-item-label> {{ t('customer.summary.webAccess') }}
<q-item-label>{{ entity.account.name }}</q-item-label> </q-item-label>
</q-item-section> <q-item>
</q-item> <q-item-section>
<q-item dense> <q-item-label caption>
<q-checkbox {{ t('customer.summary.username') }}
v-model="entity.account.active" </q-item-label>
:label="t('customer.summary.webAccess')" <q-item-label>{{ entity.account.name }}</q-item-label>
disable </q-item-section>
/> </q-item>
</q-item> <q-item dense>
</q-list> <q-checkbox
</div> v-model="entity.account.active"
<div class="col"> :label="t('customer.summary.webAccess')"
<q-list> disable
<q-item-label header class="text-h6"> />
{{ t('customer.summary.businessData') }} </q-item>
</q-item-label> </q-list>
<q-item> </div>
<q-item-section> <div class="col">
<q-item-label caption>{{ <q-list>
t('customer.summary.totalGreuge') <q-item-label header class="text-h6">
}}</q-item-label> {{ t('customer.summary.businessData') }}
<q-item-label>{{ </q-item-label>
toCurrency(entity.totalGreuge) <q-item>
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.totalGreuge') }}
<q-item v-if="entity.mana"> </q-item-label>
<q-item-section> <q-item-label>
<q-item-label caption>{{ {{ toCurrency(entity.totalGreuge) }}
t('customer.summary.mana') </q-item-label>
}}</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
toCurrency(entity.mana.mana) <q-item v-if="entity.mana">
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.mana') }}
<q-item v-if="entity.claimsRatio"> </q-item-label>
<q-item-section> <q-item-label>
<q-item-label caption> {{ toCurrency(entity.mana.mana) }}
{{ t('customer.summary.priceIncreasingRate') }} </q-item-label>
</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
toPercentage(priceIncreasingRate) <q-item v-if="entity.claimsRatio">
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.priceIncreasingRate') }}
<q-item v-if="entity.averageInvoiced"> </q-item-label>
<q-item-section> <q-item-label>
<q-item-label caption>{{ {{ toPercentage(priceIncreasingRate) }}
t('customer.summary.averageInvoiced') </q-item-label>
}}</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
toCurrency(entity.averageInvoiced.invoiced) <q-item v-if="entity.averageInvoiced">
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.averageInvoiced') }}
<q-item v-if="entity.claimsRatio"> </q-item-label>
<q-item-section> <q-item-label>
<q-item-label caption>{{ {{ toCurrency(entity.averageInvoiced.invoiced) }}
t('customer.summary.claimRate') </q-item-label>
}}</q-item-label> </q-item-section>
<q-item-label>{{ toPercentage(claimRate) }}</q-item-label> </q-item>
</q-item-section> <q-item v-if="entity.claimsRatio">
</q-item> <q-item-section>
</q-list> <q-item-label caption>
</div> {{ t('customer.summary.claimRate') }}
<div class="col"> </q-item-label>
<q-list> <q-item-label>{{ toPercentage(claimRate) }}</q-item-label>
<q-item-label header class="text-h6"> </q-item-section>
{{ t('customer.summary.financialData') }} </q-item>
</q-item-label> </q-list>
<q-item v-if="entity.debt"> </div>
<q-item-section> <div class="col">
<q-item-label caption>{{ <q-list>
t('customer.summary.risk') <q-item-label header class="text-h6">
}}</q-item-label> {{ t('customer.summary.financialData') }}
<q-item-label :class="debtWarning"> </q-item-label>
{{ toCurrency(entity.debt.debt) }} <q-item v-if="entity.debt">
</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
<q-item-section side> {{ t('customer.summary.risk') }}
<q-icon name="vn:info"> </q-item-label>
<q-tooltip>{{ <q-item-label :class="debtWarning">
t('customer.summary.riskInfo') {{ toCurrency(entity.debt.debt) }}
}}</q-tooltip> </q-item-label>
</q-icon> </q-item-section>
</q-item-section> <q-item-section side>
</q-item> <q-icon name="vn:info">
<q-item> <q-tooltip>
<q-item-section> {{ t('customer.summary.riskInfo') }}
<q-item-label caption>{{ </q-tooltip>
t('customer.summary.credit') </q-icon>
}}</q-item-label> </q-item-section>
<q-item-label :class="creditWarning"> </q-item>
{{ toCurrency(entity.credit) }} <q-item>
</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
<q-item-section side> {{ t('customer.summary.credit') }}
<q-icon name="vn:info"> </q-item-label>
<q-tooltip>{{ <q-item-label :class="creditWarning">
t('customer.summary.creditInfo') {{ toCurrency(entity.credit) }}
}}</q-tooltip> </q-item-label>
</q-icon> </q-item-section>
</q-item-section> <q-item-section side>
</q-item> <q-icon name="vn:info">
<q-item v-if="entity.creditInsurance"> <q-tooltip>
<q-item-section> {{ t('customer.summary.creditInfo') }}
<q-item-label caption>{{ </q-tooltip>
t('customer.summary.securedCredit') </q-icon>
}}</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
toCurrency(entity.creditInsurance) <q-item v-if="entity.creditInsurance">
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
<q-item-section side> {{ t('customer.summary.securedCredit') }}
<q-icon name="vn:info"> </q-item-label>
<q-tooltip>{{ <q-item-label>
t('customer.summary.securedCreditInfo') {{ toCurrency(entity.creditInsurance) }}
}}</q-tooltip> </q-item-label>
</q-icon> </q-item-section>
</q-item-section> <q-item-section side>
</q-item> <q-icon name="vn:info">
<q-item> <q-tooltip>
<q-item-section> {{ t('customer.summary.securedCreditInfo') }}
<q-item-label caption>{{ </q-tooltip>
t('customer.summary.balance') </q-icon>
}}</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
toCurrency(entity.sumRisk) || toCurrency(0) <q-item>
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
<q-item-section side> {{ t('customer.summary.balance') }}
<q-icon name="vn:info"> </q-item-label>
<q-tooltip>{{ <q-item-label>
t('customer.summary.balanceInfo') {{ toCurrency(entity.sumRisk) || toCurrency(0) }}
}}</q-tooltip> </q-item-label>
</q-icon> </q-item-section>
</q-item-section> <q-item-section side>
</q-item> <q-icon name="vn:info">
<q-item v-if="entity.defaulters"> <q-tooltip>
<q-item-section> {{ t('customer.summary.balanceInfo') }}
<q-item-label caption>{{ </q-tooltip>
t('customer.summary.balanceDue') </q-icon>
}}</q-item-label> </q-item-section>
<q-item-label :class="balanceDueWarning"> </q-item>
{{ toCurrency(balanceDue) }} <q-item v-if="entity.defaulters">
</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
<q-item-section side> {{ t('customer.summary.balanceDue') }}
<q-icon name="vn:info"> </q-item-label>
<q-tooltip>{{ <q-item-label :class="balanceDueWarning">
t('customer.summary.balanceDueInfo') {{ toCurrency(balanceDue) }}
}}</q-tooltip> </q-item-label>
</q-icon> </q-item-section>
</q-item-section> <q-item-section side>
</q-item> <q-icon name="vn:info">
<q-item v-if="entity.recovery"> <q-tooltip>
<q-item-section> {{ t('customer.summary.balanceDueInfo') }}
<q-item-label caption>{{ </q-tooltip>
t('customer.summary.recoverySince') </q-icon>
}}</q-item-label> </q-item-section>
<q-item-label>{{ </q-item>
toDate(entity.recovery.started) <q-item v-if="entity.recovery">
}}</q-item-label> <q-item-section>
</q-item-section> <q-item-label caption>
</q-item> {{ t('customer.summary.recoverySince') }}
</q-list> </q-item-label>
</div> <q-item-label>
{{ toDate(entity.recovery.started) }}
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</div>
</q-card-section>
</template> </template>
</card-summary> </card-summary>
</template> </template>

View File

@ -1,9 +1,8 @@
<script setup> <script setup>
import { onMounted, ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { toCurrency, toDate } from 'src/filters'; import { toCurrency, toDate } from 'src/filters';
import axios from 'axios';
import CardDescriptor from 'src/components/ui/CardDescriptor.vue'; import CardDescriptor from 'src/components/ui/CardDescriptor.vue';
import CustomerDescriptorPopover from 'src/pages/Customer/Card/CustomerDescriptorPopover.vue'; import CustomerDescriptorPopover from 'src/pages/Customer/Card/CustomerDescriptorPopover.vue';
@ -15,86 +14,104 @@ const $props = defineProps({
}, },
}); });
onMounted(async () => {
await fetch();
});
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const entityId = computed(() => { const entityId = computed(() => {
return $props.id || route.params.id; return $props.id || route.params.id;
}); });
const descriptor = ref();
const invoiceOut = ref(); const filter = {
async function fetch() { include: [
const filter = { {
include: [ relation: 'company',
{ scope: {
relation: 'company', fields: ['id', 'code'],
scope: {
fields: ['id', 'code'],
},
}, },
{ },
relation: 'client', {
scope: { relation: 'client',
fields: ['id', 'name', 'email'], scope: {
}, fields: ['id', 'name', 'email'],
}, },
], },
}; ],
};
const options = { params: { filter } }; function ticketFilter(invoice) {
const { data } = await axios.get(`InvoiceOuts/${entityId.value}`, options); return JSON.stringify({ refFk: invoice.ref });
if (data) invoiceOut.value = data;
} }
const filter = computed(() => {
return invoiceOut.value ? JSON.stringify({ refFk: invoiceOut.value.ref }) : null;
});
</script> </script>
<template> <template>
<card-descriptor v-if="invoiceOut" module="InvoiceOut" :data="invoiceOut" :description="invoiceOut.ref"> <card-descriptor
<template #body> ref="descriptor"
module="InvoiceOut"
:url="`InvoiceOuts/${entityId}`"
:filter="filter"
>
<template #description="{ entity }">
<span>
{{ entity.ref }}
<q-tooltip>{{ entity.ref }}</q-tooltip>
</span>
</template>
<template #body="{ entity }">
<q-list> <q-list>
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('invoiceOut.card.issued') }}</q-item-label> <q-item-label caption>
<q-item-label>{{ toDate(invoiceOut.issued) }}</q-item-label> {{ t('invoiceOut.card.issued') }}
</q-item-label>
<q-item-label>{{ toDate(entity.issued) }}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('invoiceOut.card.amount') }}</q-item-label> <q-item-label caption>
<q-item-label>{{ toCurrency(invoiceOut.amount) }}</q-item-label> {{ t('invoiceOut.card.amount') }}
</q-item-label>
<q-item-label>{{ toCurrency(entity.amount) }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section v-if="invoiceOut.company"> <q-item-section v-if="entity.client">
<q-item-label caption>{{ t('invoiceOut.card.client') }}</q-item-label> <q-item-label caption>
{{ t('invoiceOut.card.client') }}
</q-item-label>
<q-item-label class="link"> <q-item-label class="link">
{{ invoiceOut.client.name }} {{ entity.client.name }}
<q-popup-proxy> <q-popup-proxy>
<customer-descriptor-popover :id="invoiceOut.client.id" /> <customer-descriptor-popover :id="entity.client.id" />
</q-popup-proxy> </q-popup-proxy>
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
<q-item-section v-if="invoiceOut.company"> <q-item-section v-if="entity.company">
<q-item-label caption>{{ t('invoiceOut.card.company') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ invoiceOut.company.code }}</q-item-label> t('invoiceOut.card.company')
}}</q-item-label>
<q-item-label>{{ entity.company.code }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
<q-card-actions> <q-card-actions>
<q-btn <q-btn
v-if="entity.client"
size="md" size="md"
icon="vn:client" icon="vn:client"
color="primary" color="primary"
:to="{ name: 'CustomerCard', params: { id: invoiceOut.client.id } }" :to="{ name: 'CustomerCard', params: { id: entity.client.id } }"
> >
<q-tooltip>{{ t('invoiceOut.card.customerCard') }}</q-tooltip> <q-tooltip>{{ t('invoiceOut.card.customerCard') }}</q-tooltip>
</q-btn> </q-btn>
<q-btn size="md" icon="vn:ticket" color="primary" :to="{ name: 'TicketList', params: { q: filter } }"> <q-btn
size="md"
icon="vn:ticket"
color="primary"
:to="{
name: 'TicketList',
query: { q: ticketFilter(entity) },
}"
>
<q-tooltip>{{ t('invoiceOut.card.ticketList') }}</q-tooltip> <q-tooltip>{{ t('invoiceOut.card.ticketList') }}</q-tooltip>
</q-btn> </q-btn>
</q-card-actions> </q-card-actions>

View File

@ -1,12 +1,10 @@
<script setup> <script setup>
import { onMounted, computed, ref } from 'vue'; import { computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
import axios from 'axios';
import CustomerDescriptorPopover from 'src/pages/Customer/Card/CustomerDescriptorPopover.vue'; import CustomerDescriptorPopover from 'src/pages/Customer/Card/CustomerDescriptorPopover.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -16,10 +14,6 @@ const $props = defineProps({
}, },
}); });
onMounted(async () => {
await fetch();
});
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
@ -27,12 +21,35 @@ const entityId = computed(() => {
return $props.id || route.params.id; return $props.id || route.params.id;
}); });
const ticket = ref(); const filter = {
async function fetch() { include: [
const { data } = await axios.get(`Tickets/${entityId.value}/summary`); {
relation: 'client',
if (data) ticket.value = data; scope: {
} fields: ['id', 'name', 'salesPersonFk'],
include: { relation: 'salesPersonUser' },
},
},
{
relation: 'ticketState',
scope: {
include: { relation: 'state' },
},
},
{
relation: 'warehouse',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'agencyMode',
scope: {
fields: ['id', 'name'],
},
},
],
};
function stateColor(state) { function stateColor(state) {
if (state.code === 'OK') return 'text-green'; if (state.code === 'OK') return 'text-green';
@ -43,55 +60,64 @@ function stateColor(state) {
</script> </script>
<template> <template>
<skeleton-descriptor v-if="!ticket" /> <card-descriptor module="Ticket" :url="`Tickets/${entityId}`" :filter="filter">
<card-descriptor v-if="ticket" module="Ticket" :data="ticket" :description="ticket.client.name"> <template #description="{ entity }">
<!-- <template #menu> <span>
<q-item clickable v-ripple>Option 1</q-item> {{ entity.client.name }}
<q-item clickable v-ripple>Option 2</q-item> <q-tooltip>{{ entity.client.name }}</q-tooltip>
</template> --> </span>
<template #body> </template>
<template #body="{ entity }">
<q-list> <q-list>
<q-item> <q-item>
<q-item-section> <q-item-section v-if="entity.ticketState">
<q-item-label caption>{{ t('ticket.card.ticketId') }}</q-item-label>
<q-item-label>#{{ ticket.id }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.card.state') }}</q-item-label> <q-item-label caption>{{ t('ticket.card.state') }}</q-item-label>
<q-item-label :class="stateColor(ticket.ticketState.state)"> <q-item-label :class="stateColor(entity.ticketState.state)">
{{ ticket.ticketState.state.name }} {{ entity.ticketState.state.name }}
</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>
{{ t('ticket.card.shipped') }}
</q-item-label>
<q-item-label>{{ toDate(entity.shipped) }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-item-label caption>
{{ t('ticket.card.customerId') }}
</q-item-label>
<q-item-label>
<span class="link">
{{ entity.clientFk }}
<q-popup-proxy>
<customer-descriptor-popover :id="entity.client.id" />
</q-popup-proxy>
</span>
</q-item-label>
</q-item-section>
<q-item-section v-if="entity.client && entity.client.salesPersonUser">
<q-item-label caption>
{{ t('ticket.card.salesPerson') }}
</q-item-label>
<q-item-label>
{{ entity.client.salesPersonUser.name }}
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item>
<q-item-section> <q-item-section v-if="entity.warehouse">
<q-item-label caption>{{ t('ticket.card.customerId') }}</q-item-label> <q-item-label caption>
<q-item-label class="link"> {{ t('ticket.card.warehouse') }}
{{ ticket.clientFk }}
<q-popup-proxy>
<customer-descriptor-popover :id="ticket.client.id" />
</q-popup-proxy>
</q-item-label> </q-item-label>
</q-item-section> <q-item-label>{{ entity.warehouse.name }}</q-item-label>
<q-item-section>
<q-item-label caption>{{ t('ticket.card.salesPerson') }}</q-item-label>
<q-item-label>{{ ticket.client.salesPersonUser.name }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item> <q-item v-if="entity.agencyMode">
<q-item-section>
<q-item-label caption>{{ t('ticket.card.warehouse') }}</q-item-label>
<q-item-label>{{ ticket.warehouse.name }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.card.shipped') }}</q-item-label>
<q-item-label>{{ toDate(ticket.shipped) }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('ticket.card.agency') }}</q-item-label> <q-item-label caption>{{ t('ticket.card.agency') }}</q-item-label>
<q-item-label>{{ ticket.agencyMode.name }}</q-item-label> <q-item-label>{{ entity.agencyMode.name }}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
@ -101,7 +127,7 @@ function stateColor(state) {
size="md" size="md"
icon="vn:client" icon="vn:client"
color="primary" color="primary"
:to="{ name: 'CustomerCard', params: { id: ticket.clientFk } }" :to="{ name: 'CustomerCard', params: { id: entity.clientFk } }"
> >
<q-tooltip>{{ t('ticket.card.customerCard') }}</q-tooltip> <q-tooltip>{{ t('ticket.card.customerCard') }}</q-tooltip>
</q-btn> </q-btn>

View File

@ -29,6 +29,7 @@ const entityId = computed(() => $props.id || route.params.id);
const ticket = ref(); const ticket = ref();
const salesLines = ref(null); const salesLines = ref(null);
const editableStates = ref([]); const editableStates = ref([]);
async function fetch() { async function fetch() {
const { data } = await axios.get(`Tickets/${entityId.value}/summary`); const { data } = await axios.get(`Tickets/${entityId.value}/summary`);
if (data) { if (data) {