diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index d6b35d4daa..6f22a4dd9b 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -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 diff --git a/src/components/ui/CatalogItem.vue b/src/components/ui/CatalogItem.vue index ef722483be..545bfbbb40 100644 --- a/src/components/ui/CatalogItem.vue +++ b/src/components/ui/CatalogItem.vue @@ -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; } diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index e3019663c8..045f45bec5 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -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); diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 651bcefb03..4468167882 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -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; diff --git a/src/css/app.scss b/src/css/app.scss index c233b14f05..85a39b480d 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -268,3 +268,8 @@ input::-webkit-inner-spin-button { max-width: 400px; } } + +.subName { + color: var(--vn-label-color); + text-transform: uppercase; +} diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index 7d36825250..69373e23b9 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -93,6 +93,10 @@ globals: since: Since from: From to: To + quantity: Quantity + item: Item + ticket: Ticket + campaign: Campaign pageTitles: logIn: Login summary: Summary diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 8157f18038..48b2d3ad4a 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -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 diff --git a/src/pages/Customer/Card/CustomerCard.vue b/src/pages/Customer/Card/CustomerCard.vue index 229946ea2d..9562be0010 100644 --- a/src/pages/Customer/Card/CustomerCard.vue +++ b/src/pages/Customer/Card/CustomerCard.vue @@ -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', diff --git a/src/pages/Customer/Card/CustomerConsumption.vue b/src/pages/Customer/Card/CustomerConsumption.vue index 98a3115da1..835223488c 100644 --- a/src/pages/Customer/Card/CustomerConsumption.vue +++ b/src/pages/Customer/Card/CustomerConsumption.vue @@ -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> diff --git a/src/pages/Customer/Card/CustomerConsumptionFilter.vue b/src/pages/Customer/Card/CustomerConsumptionFilter.vue index 4d2c5ff3c8..31289c007c 100644 --- a/src/pages/Customer/Card/CustomerConsumptionFilter.vue +++ b/src/pages/Customer/Card/CustomerConsumptionFilter.vue @@ -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> diff --git a/src/pages/Customer/Card/CustomerSamples.vue b/src/pages/Customer/Card/CustomerSamples.vue index de998d8d38..e28e290f49 100644 --- a/src/pages/Customer/Card/CustomerSamples.vue +++ b/src/pages/Customer/Card/CustomerSamples.vue @@ -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,41 +83,34 @@ const toCustomerSamplesCreate = () => { url="ClientSamples" /> - <div class="full-width flex justify-center"> - <QPage class="card-width q-pa-lg"> - <QTable - :columns="columns" - :pagination="{ rowsPerPage: 12 }" - :rows="rows" - class="full-width q-mt-md" - row-key="id" - :no-data-label="t('globals.noResults')" - > - <template #body-cell="props"> - <QTd :props="props"> - <QTr :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) - " - > - {{ props.value }} - <WorkerDescriptorProxy - :id="props.row.userFk" - v-if="props.col.name === 'worker'" - /> - </component> - </QTr> - </QTd> - </template> - </QTable> - </QPage> - </div> + <QTable + :columns="columns" + :pagination="{ rowsPerPage: 12 }" + :rows="rows" + class="full-width q-mt-md" + row-key="id" + :no-data-label="t('globals.noResults')" + > + <template #body-cell="props"> + <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)" + :title="props.value" + > + {{ props.value }} + <WorkerDescriptorProxy + :id="props.row.userFk" + v-if="props.col.name === 'worker'" + /> + </component> + </span> + </QTd> + </template> + </QTable> <QPageSticky :offset="[18, 18]"> <QBtn @click.stop="toCustomerSamplesCreate()" color="primary" fab icon="add" /> diff --git a/src/pages/Login/ResetPassword.vue b/src/pages/Login/ResetPassword.vue index eff718e972..2751f1ceb2 100644 --- a/src/pages/Login/ResetPassword.vue +++ b/src/pages/Login/ResetPassword.vue @@ -33,7 +33,6 @@ async function onSubmit() { }; try { - console.log('newPassword: ', newPassword); await axios.post( 'VnUsers/reset-password', { newPassword: newPassword.value },