0
0
Fork 0

Added CustomerFilter

This commit is contained in:
Joan Sanchez 2023-02-14 07:04:59 +01:00
parent f9a196e7e9
commit a1ab4d84c8
8 changed files with 265 additions and 329 deletions

View File

@ -28,6 +28,7 @@ onMounted(() => {
}); });
async function search() { async function search() {
console.log('search!');
await arrayData.apply({ await arrayData.apply({
params: { params: {
search: searchText.value, search: searchText.value,

View File

@ -20,6 +20,7 @@ export function useArrayData(key, userOptions) {
const page = ref(1); const page = ref(1);
if (typeof userOptions === 'object') { if (typeof userOptions === 'object') {
if (userOptions.filter) store.filter = userOptions.filter;
if (userOptions.url) store.url = userOptions.url; if (userOptions.url) store.url = userOptions.url;
if (userOptions.limit) store.limit = userOptions.limit; if (userOptions.limit) store.limit = userOptions.limit;
if (userOptions.order) store.order = userOptions.order; if (userOptions.order) store.order = userOptions.order;
@ -38,9 +39,10 @@ export function useArrayData(key, userOptions) {
}); });
onUnmounted(() => { onUnmounted(() => {
if (arrayDataStore.get(key)) { // if (arrayDataStore.get(key)) {
arrayDataStore.clear(key); // arrayDataStore.clear(key);
} // }
// do stuff
}); });
async function fetch({ append = false }) { async function fetch({ append = false }) {
@ -53,6 +55,7 @@ export function useArrayData(key, userOptions) {
}; };
Object.assign(filter, store.userFilter); Object.assign(filter, store.userFilter);
Object.assign(filter, store.filter);
store.filter = filter; store.filter = filter;

View File

@ -2,10 +2,15 @@
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
import CustomerDescriptor from './CustomerDescriptor.vue'; import CustomerDescriptor from './CustomerDescriptor.vue';
import LeftMenu from 'components/LeftMenu.vue'; import LeftMenu from 'components/LeftMenu.vue';
import TeleportSlot from 'components/ui/TeleportSlot.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
const state = useState(); const state = useState();
</script> </script>
<template> <template>
<teleport-slot to="#searchbar">
<VnSearchbar data-key="CustomerList" />
</teleport-slot>
<q-drawer v-model="state.drawer.value" show-if-above :width="256" :breakpoint="500"> <q-drawer v-model="state.drawer.value" show-if-above :width="256" :breakpoint="500">
<q-scroll-area class="fit"> <q-scroll-area class="fit">
<CustomerDescriptor /> <CustomerDescriptor />

View File

@ -0,0 +1,151 @@
<script setup>
import { ref } from 'vue';
import FetchData from 'components/FetchData.vue';
const props = defineProps({
params: {
type: Object,
required: true
}
})
const provinces = ref([]);
const workers = ref([]);
const workersCopy = ref([]);
const zones = ref([]);
function setWorkers(data) {
workers.value = data;
workersCopy.value = data;
}
</script>
<template>
<fetch-data url="Provinces" @on-fetch="(data) => (provinces = data)" auto-load />
<fetch-data url="Zones" @on-fetch="(data) => (zones = data)" auto-load />
<fetch-data
url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }"
@on-fetch="setWorkers"
auto-load
/>
<q-list>
<!-- <q-item>
<q-item-section>
<q-input
v-model="params.search"
label="Search by id or name"
class="full-width"
lazy-rules
autofocus
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-btn
label="Search"
type="submit"
color="primary"
class="full-width"
rounded
/>
</q-item-section>
</q-item>
<q-separator /> -->
<q-item>
<q-item-section>
<q-input label="Fiscal ID" v-model="props.fi" lazy-rules>
<template #prepend>
<q-icon name="badge" size="sm"></q-icon>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Name" v-model="props.name" lazy-rules />
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Social name" v-model="props.socialName" lazy-rules />
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-select
v-model="props.salesPersonFk"
:options="workers"
option-value="id"
option-label="name"
emit-value
label="Salesperson"
map-options
use-input
:input-debounce="0"
>
<template #prepend>
<q-avatar color="orange" size="xs">
<q-img
v-if="props.salesPersonFk"
:src="`/api/Images/user/160x160/${props.salesPersonFk}/download?access_token=${token}`"
spinner-color="white"
/>
</q-avatar>
</template>
</q-select>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Phone" v-model="props.phone" lazy-rules>
<template #prepend>
<q-icon name="phone" size="sm"></q-icon>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Email" v-model="props.email" lazy-rules>
<template #prepend>
<q-icon name="email" size="sm"></q-icon>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-select
label="Province"
v-model="props.provinceFk"
:options="provinces"
option-value="id"
option-label="name"
emit-value
map-options
/>
</q-item-section>
<q-item-section>
<q-input label="City" v-model="props.city" lazy-rules />
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-select
label="Zone"
v-model="props.zoneFk"
:options="zones"
option-value="id"
option-label="name"
emit-value
map-options
/>
</q-item-section>
<q-item-section>
<q-input label="Postcode" v-model="props.postcode" lazy-rules />
</q-item-section>
</q-item>
</q-list>
</template>

View File

@ -1,16 +1,16 @@
<script setup> <script setup>
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useSession } from 'src/composables/useSession';
import { useStateStore } from 'stores/useStateStore';
import Paginate from 'src/components/PaginateData.vue'; import Paginate from 'src/components/PaginateData.vue';
import CustomerSummaryDialog from './Card/CustomerSummaryDialog.vue'; import CustomerSummaryDialog from './Card/CustomerSummaryDialog.vue';
import TeleportSlot from 'components/ui/TeleportSlot.vue'; import TeleportSlot from 'components/ui/TeleportSlot.vue';
import FetchData from 'components/FetchData.vue';
import { useSession } from 'src/composables/useSession';
import { useStateStore } from 'stores/useStateStore';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import CustomeFilter from './CustomeFilter.vue';
const state = useStateStore(); const state = useStateStore();
const router = useRouter(); const router = useRouter();
@ -35,157 +35,13 @@ function viewSummary(id) {
}, },
}); });
} }
const provinces = ref([]);
const workers = ref([]);
const workersCopy = ref([]);
const zones = ref([]);
function setWorkers(data) {
workers.value = data;
workersCopy.value = data;
}
</script> </script>
<template> <template>
<fetch-data url="Provinces" @on-fetch="(data) => (provinces = data)" auto-load />
<fetch-data url="Zones" @on-fetch="(data) => (zones = data)" auto-load />
<fetch-data
url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }"
@on-fetch="setWorkers"
auto-load
/>
<teleport-slot to="#rightPanel"> <teleport-slot to="#rightPanel">
<VnFilterPanel data-key="CustomerList"> <VnFilterPanel data-key="CustomerList">
<template #body="{ params }"> <template #body="{ params }">
<q-list> <CustomeFilter :params="params" />
<!-- <q-item>
<q-item-section>
<q-input
v-model="params.search"
label="Search by id or name"
class="full-width"
lazy-rules
autofocus
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-btn
label="Search"
type="submit"
color="primary"
class="full-width"
rounded
/>
</q-item-section>
</q-item>
<q-separator /> -->
<q-item>
<q-item-section>
<q-input label="Fiscal ID" v-model="params.fi" lazy-rules>
<template #prepend>
<q-icon name="badge" size="sm"></q-icon>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Name" v-model="params.name" lazy-rules />
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input
label="Social name"
v-model="params.socialName"
lazy-rules
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-select
v-model="params.salesPersonFk"
:options="workers"
option-value="id"
option-label="name"
emit-value
label="Salesperson"
map-options
use-input
:input-debounce="0"
>
<template #prepend>
<q-avatar color="orange" size="xs">
<q-img
v-if="params.salesPersonFk"
:src="`/api/Images/user/160x160/${params.salesPersonFk}/download?access_token=${token}`"
spinner-color="white"
/>
</q-avatar>
</template>
</q-select>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Phone" v-model="params.phone" lazy-rules>
<template #prepend>
<q-icon name="phone" size="sm"></q-icon>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-input label="Email" v-model="params.email" lazy-rules>
<template #prepend>
<q-icon name="email" size="sm"></q-icon>
</template>
</q-input>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-select
label="Province"
v-model="params.provinceFk"
:options="provinces"
option-value="id"
option-label="name"
emit-value
map-options
/>
</q-item-section>
<q-item-section>
<q-input label="City" v-model="params.city" lazy-rules />
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-select
label="Zone"
v-model="params.zoneFk"
:options="zones"
option-value="id"
option-label="name"
emit-value
map-options
/>
</q-item-section>
<q-item-section>
<q-input
label="Postcode"
v-model="params.postcode"
lazy-rules
/>
</q-item-section>
</q-item>
</q-list>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</teleport-slot> </teleport-slot>

View File

@ -2,7 +2,6 @@
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import LeftMenu from 'components/LeftMenu.vue'; import LeftMenu from 'components/LeftMenu.vue';
import TeleportSlot from 'components/ui/TeleportSlot.vue'; import TeleportSlot from 'components/ui/TeleportSlot.vue';
import CustomerSearch from './CustomerSearch.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
const stateStore = useStateStore(); const stateStore = useStateStore();
@ -10,11 +9,7 @@ const stateStore = useStateStore();
<template> <template>
<teleport-slot to="#searchbar"> <teleport-slot to="#searchbar">
<VnSearchbar data-key="CustomerList"> <VnSearchbar data-key="CustomerList" />
<template #panel="{ scope }">
<customer-search :scope="scope" />
</template>
</VnSearchbar>
</teleport-slot> </teleport-slot>
<q-drawer <q-drawer
v-model="stateStore.leftDrawer" v-model="stateStore.leftDrawer"

View File

@ -1,153 +0,0 @@
<script setup>
import { ref } from 'vue';
import { useSession } from 'composables/useSession';
import FetchData from 'components/FetchData.vue';
const session = useSession();
const props = defineProps({
scope: {
type: Object,
required: true,
},
});
const token = session.getToken();
const userParams = ref({});
async function search() {
const searchFn = props.scope.search;
await searchFn({ userParams });
}
const provinces = ref([]);
const workers = ref([]);
const workersCopy = ref([]);
const zones = ref([]);
function setWorkers(data) {
workers.value = data;
workersCopy.value = data;
}
</script>
<template>
<fetch-data url="Provinces" @on-fetch="(data) => (provinces = data)" auto-load />
<fetch-data url="Zones" @on-fetch="(data) => (zones = data)" auto-load />
<fetch-data
url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }"
@on-fetch="setWorkers"
auto-load
/>
<q-form @submit="search" class="q-gutter-y-md">
<div class="row q-gutter-x-md">
<div class="col">
<q-input v-model="userParams.search" label="Search" hint="Search by id or name" lazy-rules autofocus />
</div>
</div>
<div class="row q-gutter-x-md">
<div class="col">
<q-input label="Fiscal ID" v-model="userParams.fi" lazy-rules />
</div>
<div class="col">
<q-input label="Name" v-model="userParams.name" lazy-rules />
</div>
<div class="col">
<q-input label="Social name" v-model="userParams.socialName" lazy-rules />
</div>
</div>
<div class="row q-gutter-x-md">
<div class="col">
<q-select
v-model="userParams.salesPersonFk"
:options="workers"
option-value="id"
option-label="name"
emit-value
label="Salesperson"
map-options
use-input
:input-debounce="0"
>
<template #before>
<q-avatar color="orange">
<q-img
v-if="userParams.salesPersonFk"
:src="`/api/Images/user/160x160/${userParams.salesPersonFk}/download?access_token=${token}`"
spinner-color="white"
/>
</q-avatar>
</template>
</q-select>
</div>
</div>
<div class="row q-gutter-x-md">
<div class="col">
<q-input label="Phone" v-model="userParams.phone" lazy-rules />
</div>
<div class="col">
<q-input label="Email" v-model="userParams.email" lazy-rules />
</div>
</div>
<div class="row q-gutter-x-md">
<div class="col">
<q-select
label="Province"
v-model="userParams.provinceFk"
:options="provinces"
option-value="id"
option-label="name"
emit-value
map-options
/>
</div>
<div class="col">
<q-input label="City" v-model="userParams.city" lazy-rules />
</div>
</div>
<div class="row q-gutter-x-md">
<div class="col">
<q-select
label="Zone"
v-model="userParams.zoneFk"
:options="zones"
option-value="id"
option-label="name"
emit-value
map-options
/>
</div>
<div class="col">
<q-input label="Postcode" v-model="userParams.postcode" lazy-rules />
</div>
</div>
<!-- <q-input
label="Phone"
hint="The customer phone"
lazy-rules
:rules="[(val) => (val && val.length > 0) || 'Please type something']"
/> -->
<div>
<q-btn label="Search" type="submit" color="primary" class="full-width" rounded />
</div>
</q-form>
</template>
<i18n>
{
"en": {
"phone": "Phone"
},
"es": {
"phone": "Teléfono"
}
}
</i18n>

View File

@ -1,14 +1,24 @@
<script setup> <script setup>
import { onMounted, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useStateStore } from 'stores/useStateStore';
import Paginate from 'src/components/PaginateData.vue'; import Paginate from 'src/components/PaginateData.vue';
import { toDate, toCurrency } from 'src/filters/index'; import { toDate, toCurrency } from 'src/filters/index';
import TicketSummaryDialog from './Card/TicketSummaryDialog.vue'; import TicketSummaryDialog from './Card/TicketSummaryDialog.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import TeleportSlot from 'components/ui/TeleportSlot.vue';
// import FetchData from 'components/FetchData.vue';
const router = useRouter(); const router = useRouter();
const quasar = useQuasar(); const quasar = useQuasar();
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore();
onMounted(() => stateStore.toggleRightDrawer());
onUnmounted(() => stateStore.toggleRightDrawer());
const filter = { const filter = {
include: [ include: [
@ -60,24 +70,60 @@ function viewSummary(id) {
</script> </script>
<template> <template>
<teleport-slot to="#rightPanel">
<VnFilterPanel data-key="TicketList">
<template #body="{ params }">
<q-list>
<q-item>
<q-item-section>
<q-input
v-model="params.search"
label="Search by id or name"
class="full-width"
lazy-rules
autofocus
/>
</q-item-section>
</q-item>
</q-list>
</template>
</VnFilterPanel>
</teleport-slot>
<q-page class="q-pa-md"> <q-page class="q-pa-md">
<paginate url="/Tickets" :filter="filter" sort-by="id DESC" auto-load> <paginate
data-key="TicketList"
url="Tickets"
:filter="filter"
sort-by="id DESC"
auto-load
>
<template #body="{ rows }"> <template #body="{ rows }">
<q-card class="card" v-for="row of rows" :key="row.id"> <q-card class="card" v-for="row of rows" :key="row.id">
<q-item class="q-pa-none items-start cursor-pointer q-hoverable" v-ripple clickable> <q-item
class="q-pa-none items-start cursor-pointer q-hoverable"
v-ripple
clickable
>
<q-item-section class="q-pa-md" @click="navigate(row.id)"> <q-item-section class="q-pa-md" @click="navigate(row.id)">
<div class="text-h6">{{ row.name }}</div> <div class="text-h6">{{ row.name }}</div>
<q-item-label caption>#{{ row.id }}</q-item-label> <q-item-label caption>#{{ row.id }}</q-item-label>
<q-list> <q-list>
<q-item class="q-pa-none"> <q-item class="q-pa-none">
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('ticket.list.nickname') }}</q-item-label> <q-item-label caption>{{
t('ticket.list.nickname')
}}</q-item-label>
<q-item-label>{{ row.nickname }}</q-item-label> <q-item-label>{{ row.nickname }}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('ticket.list.state') }}</q-item-label> <q-item-label caption>{{
t('ticket.list.state')
}}</q-item-label>
<q-item-label> <q-item-label>
<q-chip :color="stateColor(row.ticketState)" dense> <q-chip
:color="stateColor(row.ticketState)"
dense
>
{{ row.ticketState.state.name }} {{ row.ticketState.state.name }}
</q-chip> </q-chip>
</q-item-label> </q-item-label>
@ -85,33 +131,65 @@ function viewSummary(id) {
</q-item> </q-item>
<q-item class="q-pa-none"> <q-item class="q-pa-none">
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('ticket.list.shipped') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ toDate(row.shipped) }}</q-item-label> t('ticket.list.shipped')
}}</q-item-label>
<q-item-label>{{
toDate(row.shipped)
}}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('ticket.list.landed') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ toDate(row.landed) }}</q-item-label> t('ticket.list.landed')
}}</q-item-label>
<q-item-label>{{
toDate(row.landed)
}}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item class="q-pa-none"> <q-item class="q-pa-none">
<q-item-section v-if="row.client.salesPersonUser"> <q-item-section v-if="row.client.salesPersonUser">
<q-item-label caption>{{ t('ticket.list.salesPerson') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ row.client.salesPersonUser.name }}</q-item-label> t('ticket.list.salesPerson')
}}</q-item-label>
<q-item-label>{{
row.client.salesPersonUser.name
}}</q-item-label>
</q-item-section> </q-item-section>
<q-item-section> <q-item-section>
<q-item-label caption>{{ t('ticket.list.total') }}</q-item-label> <q-item-label caption>{{
<q-item-label>{{ toCurrency(row.totalWithVat) }}</q-item-label> t('ticket.list.total')
}}</q-item-label>
<q-item-label>{{
toCurrency(row.totalWithVat)
}}</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>
</q-item-section> </q-item-section>
<q-separator vertical /> <q-separator vertical />
<q-card-actions vertical class="justify-between"> <q-card-actions vertical class="justify-between">
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)"> <q-btn
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip> flat
round
color="orange"
icon="arrow_circle_right"
@click="navigate(row.id)"
>
<q-tooltip>{{
t('components.smartCard.openCard')
}}</q-tooltip>
</q-btn> </q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="viewSummary(row.id)"> <q-btn
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip> flat
round
color="grey-7"
icon="preview"
@click="viewSummary(row.id)"
>
<q-tooltip>{{
t('components.smartCard.openSummary')
}}</q-tooltip>
</q-btn> </q-btn>
</q-card-actions> </q-card-actions>
</q-item> </q-item>