0
0
Fork 0

feat: customer consumption

This commit is contained in:
Alex Moreno 2024-08-16 15:16:35 +02:00
parent 793001be6e
commit e45e551526
12 changed files with 249 additions and 68 deletions

View File

@ -67,7 +67,7 @@ const $props = defineProps({
},
hasSubToolbar: {
type: Boolean,
default: true,
default: null,
},
disableOption: {
type: Object,
@ -341,7 +341,7 @@ defineExpose({
:search-url="searchUrl"
:disable-infinite-scroll="isTableMode"
@save-changes="reload"
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
:has-sub-toolbar="$props.hasSubToolbar ?? isEditable"
:auto-load="hasParams || $attrs['auto-load']"
>
<template

View File

@ -127,11 +127,6 @@ const dialog = ref(null);
flex-direction: column;
gap: 4px;
.subName {
color: var(--vn-label-color);
text-transform: uppercase;
}
p {
margin-bottom: 0;
}

View File

@ -3,6 +3,7 @@ import { onMounted, ref, computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useArrayData } from 'composables/useArrayData';
import { useRoute } from 'vue-router';
import { date } from 'quasar';
import toDate from 'filters/toDate';
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
@ -190,6 +191,7 @@ async function remove(key) {
}
function formatValue(value) {
if (value instanceof Date) return date.formatDate(value, 'DD/MM/YYYY');
if (typeof value === 'boolean') return value ? t('Yes') : t('No');
if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);

View File

@ -86,12 +86,26 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
Object.assign(filter, store.userFilter, exprFilter);
let where;
if (filter?.where || store.filter?.where)
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
// ARRAY DATA FALLA AL JUNTAR WHERE'S
console.log(
'userParams?.filter?.where: ',
userParams?.filter?.where,
filter?.where,
store.filter?.where
);
if ((userParams?.filter?.where, filter?.where || store.filter?.where))
where = Object.assign(
userParams?.filter?.where ?? {},
filter?.where ?? {},
store.filter?.where ?? {}
);
Object.assign(filter, store.filter);
filter.where = where;
console.log('where: ', where);
const params = { filter };
console.log('params: ', params);
delete userParams?.filter;
Object.assign(params, userParams);
params.filter.skip = store.skip;
if (store.order && store.order.length) params.filter.order = store.order;

View File

@ -268,3 +268,8 @@ input::-webkit-inner-spin-button {
max-width: 400px;
}
}
.subName {
color: var(--vn-label-color);
text-transform: uppercase;
}

View File

@ -93,6 +93,10 @@ globals:
since: Since
from: From
to: To
quantity: Quantity
item: Item
ticket: Ticket
campaign: Campaign
pageTitles:
logIn: Login
summary: Summary

View File

@ -93,6 +93,10 @@ globals:
since: Desde
from: Desde
to: Hasta
quantity: Cantidad
item: Artículo
ticket: Ticket
campaign: Campaña
pageTitles:
logIn: Inicio de sesión
summary: Resumen

View File

@ -1,14 +1,20 @@
<script setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import VnCard from 'components/common/VnCard.vue';
import CustomerDescriptor from './CustomerDescriptor.vue';
import CustomerFilter from '../CustomerFilter.vue';
const route = useRoute();
const routeName = computed(() => route.name);
</script>
<template>
<VnCard
data-key="Client"
base-url="Clients"
:descriptor="CustomerDescriptor"
:filter-panel="CustomerFilter"
:filter-panel="routeName != 'CustomerConsumption' && CustomerFilter"
search-data-key="CustomerList"
:searchbar-props="{
url: 'Clients/extendedListFilter',

View File

@ -1,17 +1,183 @@
<script setup>
import { ref, computed, onBeforeMount } from 'vue';
import axios from 'axios';
import { useI18n } from 'vue-i18n';
import CustomerConsumptionFilter from './CustomerConsumptionFilter.vue';
import { useStateStore } from 'src/stores/useStateStore';
import { toDate } from 'src/filters/index';
import { useRoute } from 'vue-router';
import VnTable from 'components/VnTable/VnTable.vue';
import FetchedTags from 'components/ui/FetchedTags.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
const { t } = useI18n();
const route = useRoute();
const campaignList = ref();
const columns = computed(() => [
{
name: 'search',
align: 'left',
label: t('globals.search'),
visible: false,
},
{
name: 'itemFk',
align: 'left',
label: t('globals.item'),
columnClass: 'shrink',
columnFilter: {
name: 'itemId',
},
},
{
name: 'ticketFk',
align: 'left',
label: t('globals.ticket'),
columnFilter: {
inWhere: true,
},
},
{
name: 'shipped',
align: 'left',
label: t('globals.shipped'),
format: ({ shipped }) => toDate(shipped),
columnFilter: false,
},
{
name: 'description',
align: 'left',
label: t('globals.description'),
},
{
name: 'quantity',
label: t('globals.quantity'),
},
{
name: 'grouped',
label: t('Group by items'),
component: 'checkbox',
visible: false,
orderBy: false,
},
]);
onBeforeMount(async () => {
campaignList.value = (await axios('Campaigns/latest')).data;
});
const filter = computed(() => {
const minDate = Date.vnNew();
minDate.setHours(0, 0, 0, 0);
minDate.setMonth(minDate.getMonth() - 2);
const maxDate = Date.vnNew();
maxDate.setHours(23, 59, 59, 59);
return {
campaign: campaignList.value[0]?.id,
from: minDate,
to: maxDate,
filter: {
where: {
clientFk: route.params.id,
},
},
};
});
</script>
<template>
<Teleport to="#right-panel" v-if="useStateStore().isHeaderMounted()">
<CustomerConsumptionFilter data-key="CustomerConsumption" />
</Teleport>
<VnTable
v-if="campaignList"
data-key="CustomerConsumption"
url="Clients/consumption"
:order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
:columns="columns"
search-url="consumption"
:user-params="filter"
:default-remove="false"
:default-reset="false"
:default-save="false"
:has-sub-toolbar="true"
auto-load
>
<template #moreBeforeActions>
<QBtn
color="primary"
icon="delete"
flat
@click="remove(selected)"
:disable="!selected?.length"
:title="t('globals.remove')"
/>
</template>
<template #column-itemFk="{ row }">
<span class="link">
{{ row.itemFk }}
<ItemDescriptorProxy :id="row.itemFk" />
</span>
</template>
<template #column-ticketFk="{ row }">
<span class="link">
{{ row.ticketFk }}
<TicketDescriptorProxy :id="row.ticketFk" />
</span>
</template>
<template #column-description="{ row }">
<div>{{ row.concept }}</div>
<div v-if="row.subName" class="subName">
{{ row.subName }}
</div>
<FetchedTags :item="row" :max-length="3" />
</template>
<template #moreFilterPanel="{ params }">
<div class="column no-wrap flex-center q-gutter-y-md q-mt-xs q-pr-xl">
<VnSelect
v-model="params.campaign"
:options="campaignList"
:label="t('globals.campaign')"
:filled="true"
class="q-px-sm q-pt-none fit"
dense
option-label="code"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.code }}
{{
new Date(scope.opt?.dated).getFullYear()
}}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnInputDate
v-model="params.to"
:label="t('globals.from')"
:filled="true"
class="q-px-xs q-pt-none fit"
dense
/>
<VnInputDate
v-model="params.from"
:label="t('globals.from')"
:filled="true"
class="q-px-xs q-pt-none fit"
dense
/>
</div>
</template>
</VnTable>
</template>
<i18n>
es:
Enter a new search: Introduce una nueva búsqueda
Group by items: Agrupar por artículos
</i18n>

View File

@ -10,7 +10,7 @@ const { t } = useI18n();
defineProps({ dataKey: { type: String, required: true } });
</script>
<template>
<VnFilterPanel :data-key="dataKey" :search-button="true">
<VnFilterPanel :data-key="dataKey" search-url="consumption">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>

View File

@ -26,27 +26,20 @@ const filter = {
limit: 20,
};
const basicSpan = {
component: 'span',
props: () => {},
event: () => {},
};
const tableColumnComponents = {
sent: {
component: 'span',
props: () => {},
event: () => {},
},
description: {
component: 'span',
props: () => {},
event: () => {},
},
sent: basicSpan,
description: basicSpan,
worker: {
component: QBtn,
props: () => ({ flat: true, color: 'blue', noCaps: true }),
event: () => {},
},
company: {
component: 'span',
props: () => {},
props: () => ({ class: 'link' }),
event: () => {},
},
company: basicSpan,
};
const columns = computed(() => [
@ -90,8 +83,6 @@ const toCustomerSamplesCreate = () => {
url="ClientSamples"
/>
<div class="full-width flex justify-center">
<QPage class="card-width q-pa-lg">
<QTable
:columns="columns"
:pagination="{ rowsPerPage: 12 }"
@ -101,17 +92,14 @@ const toCustomerSamplesCreate = () => {
:no-data-label="t('globals.noResults')"
>
<template #body-cell="props">
<QTd :props="props">
<QTr :props="props" class="cursor-pointer">
<QTd auto-width :props="props">
<span :props="props" class="cursor-pointer">
<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)
"
v-bind="tableColumnComponents[props.col.name].props(props)"
@click="tableColumnComponents[props.col.name].event(props)"
:title="props.value"
>
{{ props.value }}
<WorkerDescriptorProxy
@ -119,12 +107,10 @@ const toCustomerSamplesCreate = () => {
v-if="props.col.name === 'worker'"
/>
</component>
</QTr>
</span>
</QTd>
</template>
</QTable>
</QPage>
</div>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="toCustomerSamplesCreate()" color="primary" fab icon="add" />

View File

@ -33,7 +33,6 @@ async function onSubmit() {
};
try {
console.log('newPassword: ', newPassword);
await axios.post(
'VnUsers/reset-password',
{ newPassword: newPassword.value },