refactor: 03 => screen.xs fetch scroll

This commit is contained in:
puriphatt 2025-01-30 10:10:15 +07:00
parent 508e6d3f5b
commit ef81a93690
2 changed files with 565 additions and 513 deletions

View file

@ -84,7 +84,6 @@ import { DialogContainer, DialogHeader } from 'components/dialog';
import KebabAction from 'src/components/shared/KebabAction.vue'; import KebabAction from 'src/components/shared/KebabAction.vue';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import FormEmployeeVisa from 'components/03_customer-management/FormEmployeeVisa.vue'; import FormEmployeeVisa from 'components/03_customer-management/FormEmployeeVisa.vue';
import { group } from 'node:console';
import PaginationPageSize from 'src/components/PaginationPageSize.vue'; import PaginationPageSize from 'src/components/PaginationPageSize.vue';
import { AddButton } from 'components/button'; import { AddButton } from 'components/button';
@ -224,10 +223,12 @@ watch(
if (tabName === 'employer') { if (tabName === 'employer') {
currentPageCustomer.value = 1; currentPageCustomer.value = 1;
currentBtnOpen.value = []; currentBtnOpen.value = [];
listCustomer.value = [];
await fetchListCustomer(true); await fetchListCustomer(true);
} }
if (tabName === 'employee') { if (tabName === 'employee') {
currentPageEmployee.value = 1; currentPageEmployee.value = 1;
listEmployee.value = [];
await fetchListEmployee({ fetchStats: true }); await fetchListEmployee({ fetchStats: true });
} }
@ -383,8 +384,8 @@ async function fetchListCustomer(fetchStats = false) {
customerType: ( customerType: (
{ {
all: undefined, all: undefined,
customerLegalEntity: 'CORP', customerLegalEntity: CustomerType.Corporate,
customerNaturalPerson: 'PERS', customerNaturalPerson: CustomerType.Person,
} as const } as const
)[customerTypeSelected.value.value], )[customerTypeSelected.value.value],
}); });
@ -392,7 +393,9 @@ async function fetchListCustomer(fetchStats = false) {
if (resultList) { if (resultList) {
currentPageCustomer.value = resultList.page; currentPageCustomer.value = resultList.page;
maxPageCustomer.value = Math.ceil(resultList.total / pageSize.value); maxPageCustomer.value = Math.ceil(resultList.total / pageSize.value);
listCustomer.value = resultList.result; $q.screen.xs
? listCustomer.value.push(...resultList.result)
: (listCustomer.value = resultList.result);
} }
if (fetchStats) { if (fetchStats) {
@ -426,7 +429,9 @@ async function fetchListEmployee(opt?: {
maxPageEmployee.value = Math.ceil( maxPageEmployee.value = Math.ceil(
resultListEmployee.total / pageSize.value, resultListEmployee.total / pageSize.value,
); );
listEmployee.value = resultListEmployee.result; $q.screen.xs
? listEmployee.value.push(...resultListEmployee.result)
: (listEmployee.value = resultListEmployee.result);
} }
if (opt && opt.fetchStats) if (opt && opt.fetchStats)
@ -1098,7 +1103,7 @@ const emptyCreateDialog = ref(false);
class="q-px-md row q-gutter-x-sm items-center" class="q-px-md row q-gutter-x-sm items-center"
> >
<nav <nav
class="col rounded q-pa-sm text-center app-text-muted" class="col rounded q-pa-sm text-center app-text-muted text-caption"
:class="{ :class="{
'active-tab-sm': customerTypeSelected.value === v, 'active-tab-sm': customerTypeSelected.value === v,
'bordered surface-1': customerTypeSelected.value !== v, 'bordered surface-1': customerTypeSelected.value !== v,
@ -1198,9 +1203,25 @@ const emptyCreateDialog = ref(false);
<NoData :not-found="!!inputSearch" /> <NoData :not-found="!!inputSearch" />
</div> </div>
<div <article
v-if="listCustomer.length !== 0" v-if="listCustomer.length !== 0"
class="col q-pa-md scroll full-width" class="col q-pa-md scroll full-width"
>
<q-infinite-scroll
:offset="100"
@load="
(_, done) => {
if (
$q.screen.gt.xs ||
currentPageCustomer === maxPageCustomer
)
return;
currentPageCustomer = currentPageCustomer + 1;
fetchListCustomer().then(() =>
done(currentPageCustomer >= maxPageCustomer),
);
}
"
> >
<q-table <q-table
flat flat
@ -1317,7 +1338,8 @@ const emptyCreateDialog = ref(false);
<div class="col app-text-muted"> <div class="col app-text-muted">
{{ {{
props.row.customerType === 'CORP' props.row.customerType === 'CORP'
? props.row.branch[0]?.registerNameEN || '-' ? props.row.branch[0]?.registerNameEN ||
'-'
: capitalizeFirstLetter( : capitalizeFirstLetter(
props.row.branch[0].namePrefix, props.row.branch[0].namePrefix,
) + ) +
@ -1544,7 +1566,8 @@ const emptyCreateDialog = ref(false);
} }
" "
@edit=" @edit="
(item: any) => editEmployeeFormPersonal(item.id) (item: any) =>
editEmployeeFormPersonal(item.id)
" "
@delete=" @delete="
(item: any) => { (item: any) => {
@ -1601,7 +1624,9 @@ const emptyCreateDialog = ref(false);
:inactive="props.row.status === 'INACTIVE'" :inactive="props.row.status === 'INACTIVE'"
:field-selected=" :field-selected="
fieldSelected.filter((v) => { fieldSelected.filter((v) => {
return columnsCustomer.some((c) => c.name === v); return columnsCustomer.some(
(c) => c.name === v,
);
}) })
" "
> >
@ -1663,7 +1688,9 @@ const emptyCreateDialog = ref(false);
v !== 'titleName' && v !== 'titleName' &&
v !== 'address' && v !== 'address' &&
v !== 'contactName' && v !== 'contactName' &&
columnsCustomer.some((c) => c.name === v) columnsCustomer.some(
(c) => c.name === v,
)
); );
}) })
.sort((lhs, rhs) => { .sort((lhs, rhs) => {
@ -1672,7 +1699,9 @@ const emptyCreateDialog = ref(false);
...columnsCustomer, ...columnsCustomer,
]; ];
return ( return (
fields.findIndex((i) => i.name === lhs) - fields.findIndex(
(i) => i.name === lhs,
) -
fields.findIndex((i) => i.name === rhs) fields.findIndex((i) => i.name === rhs)
); );
})" })"
@ -1692,7 +1721,8 @@ const emptyCreateDialog = ref(false);
props.row.branch[0].jobPosition, props.row.branch[0].jobPosition,
) )
: key === 'officeTel' : key === 'officeTel'
? props.row.branch[0].officeTel || '-' ? props.row.branch[0].officeTel ||
'-'
: '' : ''
}} }}
</span> </span>
@ -1729,10 +1759,22 @@ const emptyCreateDialog = ref(false);
</div> </div>
</template> </template>
</q-table> </q-table>
</div> <template v-slot:loading>
<div <div
v-if="listCustomer.length !== 0" v-if="
$q.screen.lt.sm &&
currentPageCustomer !== maxPageCustomer
"
class="row justify-center"
>
<q-spinner-dots color="primary" size="40px" />
</div>
</template>
</q-infinite-scroll>
</article>
<footer
v-if="listCustomer.length !== 0 && $q.screen.gt.xs"
class="row justify-between items-center q-px-md q-py-sm" class="row justify-between items-center q-px-md q-py-sm"
> >
<div class="row col-4 items-center"> <div class="row col-4 items-center">
@ -1775,7 +1817,7 @@ const emptyCreateDialog = ref(false);
" "
/> />
</div> </div>
</div> </footer>
</template> </template>
<!-- employee --> <!-- employee -->
@ -1792,9 +1834,25 @@ const emptyCreateDialog = ref(false);
<NoData :not-found="!!inputSearch" /> <NoData :not-found="!!inputSearch" />
</div> </div>
<div <article
v-if="listEmployee.length !== 0" v-if="listEmployee.length !== 0"
class="surface-2 q-pa-md scroll col full-width" class="surface-2 q-pa-md scroll col full-width"
>
<q-infinite-scroll
:offset="100"
@load="
(_, done) => {
if (
$q.screen.gt.xs ||
currentPageEmployee === maxPageEmployee
)
return;
currentPageEmployee = currentPageEmployee + 1;
fetchListEmployee().then(() =>
done(currentPageEmployee >= maxPageEmployee),
);
}
"
> >
<TableEmpoloyee <TableEmpoloyee
v-model:page-size="pageSize" v-model:page-size="pageSize"
@ -1832,9 +1890,21 @@ const emptyCreateDialog = ref(false);
} }
" "
/> />
</div> <template v-slot:loading>
<div <div
v-if="listEmployee.length !== 0" v-if="
$q.screen.lt.sm &&
currentPageEmployee !== maxPageEmployee
"
class="row justify-center"
>
<q-spinner-dots color="primary" size="40px" />
</div>
</template>
</q-infinite-scroll>
</article>
<footer
v-if="listEmployee.length !== 0 && $q.screen.gt.xs"
class="row justify-between items-center q-px-md q-py-sm" class="row justify-between items-center q-px-md q-py-sm"
> >
<div class="row col-4 items-center"> <div class="row col-4 items-center">
@ -1875,7 +1945,7 @@ const emptyCreateDialog = ref(false);
" "
/> />
</div> </div>
</div> </footer>
</template> </template>
<template <template

View file

@ -13,6 +13,7 @@ import { useInstitution } from 'src/stores/institution';
import { Institution, InstitutionPayload } from 'src/stores/institution/types'; import { Institution, InstitutionPayload } from 'src/stores/institution/types';
import { formatAddress } from 'src/utils/address'; import { formatAddress } from 'src/utils/address';
import PaginationPageSize from 'src/components/PaginationPageSize.vue';
import PaginationComponent from 'src/components/PaginationComponent.vue'; import PaginationComponent from 'src/components/PaginationComponent.vue';
import KebabAction from 'src/components/shared/KebabAction.vue'; import KebabAction from 'src/components/shared/KebabAction.vue';
import StatCardComponent from 'src/components/StatCardComponent.vue'; import StatCardComponent from 'src/components/StatCardComponent.vue';
@ -756,26 +757,7 @@ watch(
{{ $t('general.recordPerPage') }} {{ $t('general.recordPerPage') }}
</div> </div>
<div> <div>
<q-btn-dropdown <PaginationPageSize v-model="pageSize" />
dense
unelevated
:label="pageSize"
class="bordered q-pl-md"
>
<q-list>
<q-item
v-for="v in [10, 30, 50, 100, 500, 1000]"
:key="v"
clickable
v-close-popup
@click="pageSize = v"
>
<q-item-section>
<q-item-label>{{ v }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div> </div>
</div> </div>
</div> </div>