forked from verdnatura/salix-front
feat: customer consumption
This commit is contained in:
parent
793001be6e
commit
e45e551526
|
@ -67,7 +67,7 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
hasSubToolbar: {
|
hasSubToolbar: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: null,
|
||||||
},
|
},
|
||||||
disableOption: {
|
disableOption: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -341,7 +341,7 @@ defineExpose({
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
:disable-infinite-scroll="isTableMode"
|
:disable-infinite-scroll="isTableMode"
|
||||||
@save-changes="reload"
|
@save-changes="reload"
|
||||||
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
:has-sub-toolbar="$props.hasSubToolbar ?? isEditable"
|
||||||
:auto-load="hasParams || $attrs['auto-load']"
|
:auto-load="hasParams || $attrs['auto-load']"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
|
|
|
@ -127,11 +127,6 @@ const dialog = ref(null);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
||||||
.subName {
|
|
||||||
color: var(--vn-label-color);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { onMounted, ref, computed, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { date } from 'quasar';
|
||||||
import toDate from 'filters/toDate';
|
import toDate from 'filters/toDate';
|
||||||
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
|
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
|
||||||
|
|
||||||
|
@ -190,6 +191,7 @@ async function remove(key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatValue(value) {
|
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 (typeof value === 'boolean') return value ? t('Yes') : t('No');
|
||||||
if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);
|
if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,26 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
|
||||||
|
|
||||||
Object.assign(filter, store.userFilter, exprFilter);
|
Object.assign(filter, store.userFilter, exprFilter);
|
||||||
let where;
|
let where;
|
||||||
if (filter?.where || store.filter?.where)
|
// ARRAY DATA FALLA AL JUNTAR WHERE'S
|
||||||
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
|
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);
|
Object.assign(filter, store.filter);
|
||||||
filter.where = where;
|
filter.where = where;
|
||||||
|
console.log('where: ', where);
|
||||||
const params = { filter };
|
const params = { filter };
|
||||||
|
console.log('params: ', params);
|
||||||
|
|
||||||
|
delete userParams?.filter;
|
||||||
Object.assign(params, userParams);
|
Object.assign(params, userParams);
|
||||||
params.filter.skip = store.skip;
|
params.filter.skip = store.skip;
|
||||||
if (store.order && store.order.length) params.filter.order = store.order;
|
if (store.order && store.order.length) params.filter.order = store.order;
|
||||||
|
|
|
@ -268,3 +268,8 @@ input::-webkit-inner-spin-button {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subName {
|
||||||
|
color: var(--vn-label-color);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
|
@ -93,6 +93,10 @@ globals:
|
||||||
since: Since
|
since: Since
|
||||||
from: From
|
from: From
|
||||||
to: To
|
to: To
|
||||||
|
quantity: Quantity
|
||||||
|
item: Item
|
||||||
|
ticket: Ticket
|
||||||
|
campaign: Campaign
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Login
|
logIn: Login
|
||||||
summary: Summary
|
summary: Summary
|
||||||
|
|
|
@ -93,6 +93,10 @@ globals:
|
||||||
since: Desde
|
since: Desde
|
||||||
from: Desde
|
from: Desde
|
||||||
to: Hasta
|
to: Hasta
|
||||||
|
quantity: Cantidad
|
||||||
|
item: Artículo
|
||||||
|
ticket: Ticket
|
||||||
|
campaign: Campaña
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Inicio de sesión
|
logIn: Inicio de sesión
|
||||||
summary: Resumen
|
summary: Resumen
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import VnCard from 'components/common/VnCard.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import CustomerDescriptor from './CustomerDescriptor.vue';
|
import CustomerDescriptor from './CustomerDescriptor.vue';
|
||||||
import CustomerFilter from '../CustomerFilter.vue';
|
import CustomerFilter from '../CustomerFilter.vue';
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const routeName = computed(() => route.name);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnCard
|
<VnCard
|
||||||
data-key="Client"
|
data-key="Client"
|
||||||
base-url="Clients"
|
base-url="Clients"
|
||||||
:descriptor="CustomerDescriptor"
|
:descriptor="CustomerDescriptor"
|
||||||
:filter-panel="CustomerFilter"
|
:filter-panel="routeName != 'CustomerConsumption' && CustomerFilter"
|
||||||
search-data-key="CustomerList"
|
search-data-key="CustomerList"
|
||||||
:searchbar-props="{
|
:searchbar-props="{
|
||||||
url: 'Clients/extendedListFilter',
|
url: 'Clients/extendedListFilter',
|
||||||
|
|
|
@ -1,17 +1,183 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref, computed, onBeforeMount } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import CustomerConsumptionFilter from './CustomerConsumptionFilter.vue';
|
import { toDate } from 'src/filters/index';
|
||||||
import { useStateStore } from 'src/stores/useStateStore';
|
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 { 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="#right-panel" v-if="useStateStore().isHeaderMounted()">
|
<VnTable
|
||||||
<CustomerConsumptionFilter data-key="CustomerConsumption" />
|
v-if="campaignList"
|
||||||
</Teleport>
|
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>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Enter a new search: Introduce una nueva búsqueda
|
Enter a new search: Introduce una nueva búsqueda
|
||||||
|
Group by items: Agrupar por artículos
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -10,7 +10,7 @@ const { t } = useI18n();
|
||||||
defineProps({ dataKey: { type: String, required: true } });
|
defineProps({ dataKey: { type: String, required: true } });
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnFilterPanel :data-key="dataKey" :search-button="true">
|
<VnFilterPanel :data-key="dataKey" search-url="consumption">
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||||
|
|
|
@ -26,27 +26,20 @@ const filter = {
|
||||||
limit: 20,
|
limit: 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const basicSpan = {
|
||||||
|
component: 'span',
|
||||||
|
props: () => {},
|
||||||
|
event: () => {},
|
||||||
|
};
|
||||||
const tableColumnComponents = {
|
const tableColumnComponents = {
|
||||||
sent: {
|
sent: basicSpan,
|
||||||
component: 'span',
|
description: basicSpan,
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
worker: {
|
worker: {
|
||||||
component: QBtn,
|
|
||||||
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
company: {
|
|
||||||
component: 'span',
|
component: 'span',
|
||||||
props: () => {},
|
props: () => ({ class: 'link' }),
|
||||||
event: () => {},
|
event: () => {},
|
||||||
},
|
},
|
||||||
|
company: basicSpan,
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
|
@ -90,41 +83,34 @@ const toCustomerSamplesCreate = () => {
|
||||||
url="ClientSamples"
|
url="ClientSamples"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="full-width flex justify-center">
|
<QTable
|
||||||
<QPage class="card-width q-pa-lg">
|
:columns="columns"
|
||||||
<QTable
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
:columns="columns"
|
:rows="rows"
|
||||||
:pagination="{ rowsPerPage: 12 }"
|
class="full-width q-mt-md"
|
||||||
:rows="rows"
|
row-key="id"
|
||||||
class="full-width q-mt-md"
|
:no-data-label="t('globals.noResults')"
|
||||||
row-key="id"
|
>
|
||||||
:no-data-label="t('globals.noResults')"
|
<template #body-cell="props">
|
||||||
>
|
<QTd auto-width :props="props">
|
||||||
<template #body-cell="props">
|
<span :props="props" class="cursor-pointer">
|
||||||
<QTd :props="props">
|
<component
|
||||||
<QTr :props="props" class="cursor-pointer">
|
:is="tableColumnComponents[props.col.name].component"
|
||||||
<component
|
class="col-content"
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||||
class="col-content"
|
@click="tableColumnComponents[props.col.name].event(props)"
|
||||||
v-bind="
|
:title="props.value"
|
||||||
tableColumnComponents[props.col.name].props(props)
|
>
|
||||||
"
|
{{ props.value }}
|
||||||
@click="
|
<WorkerDescriptorProxy
|
||||||
tableColumnComponents[props.col.name].event(props)
|
:id="props.row.userFk"
|
||||||
"
|
v-if="props.col.name === 'worker'"
|
||||||
>
|
/>
|
||||||
{{ props.value }}
|
</component>
|
||||||
<WorkerDescriptorProxy
|
</span>
|
||||||
:id="props.row.userFk"
|
</QTd>
|
||||||
v-if="props.col.name === 'worker'"
|
</template>
|
||||||
/>
|
</QTable>
|
||||||
</component>
|
|
||||||
</QTr>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
</QPage>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerSamplesCreate()" color="primary" fab icon="add" />
|
<QBtn @click.stop="toCustomerSamplesCreate()" color="primary" fab icon="add" />
|
||||||
|
|
|
@ -33,7 +33,6 @@ async function onSubmit() {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('newPassword: ', newPassword);
|
|
||||||
await axios.post(
|
await axios.post(
|
||||||
'VnUsers/reset-password',
|
'VnUsers/reset-password',
|
||||||
{ newPassword: newPassword.value },
|
{ newPassword: newPassword.value },
|
||||||
|
|
Loading…
Reference in New Issue