feat: add date range selection to customer and employee management

This commit is contained in:
puriphatt 2025-04-17 17:03:16 +07:00
parent 461dd359b1
commit 36cef7ceb6
3 changed files with 64 additions and 30 deletions

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, watch, onMounted, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { QSelect, useQuasar } from 'quasar';
import { useQuasar } from 'quasar';
import { useRoute, useRouter } from 'vue-router';
import { getUserId, getRole } from 'src/services/keycloak';
import { baseUrl, setPrefixName, waitAll } from 'src/stores/utils';
@ -86,6 +86,7 @@ import { nextTick } from 'vue';
import FormEmployeeVisa from 'components/03_customer-management/FormEmployeeVisa.vue';
import PaginationPageSize from 'src/components/PaginationPageSize.vue';
import { AddButton } from 'components/button';
import AdvanceSearch from 'src/components/shared/AdvanceSearch.vue';
const { t, locale } = useI18n();
const $q = useQuasar();
@ -101,7 +102,6 @@ const employeeFormStore = useEmployeeForm();
const optionStore = useOptionStore();
const ocrStore = useOcrStore();
const refFilter = ref<InstanceType<typeof QSelect>>();
const mrz = ref<Awaited<ReturnType<typeof parseResultMRZ>>>();
const {
@ -189,6 +189,7 @@ const statsCustomerType = ref<CustomerStats>({
});
// NOTE: Page State
const searchDate = ref<string[]>([]);
const currentTab = ref<'employer' | 'employee'>('employer');
const inputSearch = ref('');
const currentStatus = ref<Status | 'All'>('All');
@ -226,8 +227,16 @@ const dialogEmployeeImageUpload = ref<InstanceType<typeof ImageUploadDialog>>();
const imageList = ref<{ selectedImage: string; list: string[] }>();
watch(() => route.name, init);
watch(
[currentTab, currentStatus, inputSearch, customerTypeSelected, pageSize],
async ([tabName]) => {
[
currentTab,
currentStatus,
inputSearch,
customerTypeSelected,
pageSize,
searchDate,
],
async ([tabName], [oldTabName]) => {
if (tabName !== oldTabName) searchDate.value = [];
if (tabName === 'employer') {
currentPageCustomer.value = 1;
currentBtnOpen.value = [];
@ -317,6 +326,8 @@ async function fetchListCustomer(fetchStats = false, mobileFetch?: boolean) {
? 'ACTIVE'
: 'INACTIVE',
query: inputSearch.value,
startDate: searchDate.value[0],
endDate: searchDate.value[1],
customerType: (
{
all: undefined,
@ -370,6 +381,8 @@ async function fetchListEmployee(opt?: {
query: inputSearch.value,
passport: true,
visa: true,
startDate: searchDate.value[0],
endDate: searchDate.value[1],
});
if (resultListEmployee) {
maxPageEmployee.value = Math.ceil(
@ -775,26 +788,43 @@ const emptyCreateDialog = ref(false);
<template #prepend>
<q-icon name="mdi-magnify" />
</template>
<template v-if="$q.screen.lt.md" v-slot:append>
<span class="row">
<q-separator vertical />
<q-btn
icon="mdi-filter-variant"
unelevated
class="q-ml-sm"
padding="4px"
size="sm"
rounded
@click="refFilter?.showPopup"
<template v-slot:append>
<q-separator vertical inset class="q-mr-xs" />
<AdvanceSearch
v-model="searchDate"
:active="$q.screen.lt.md && currentStatus !== 'All'"
>
<div
v-if="$q.screen.lt.md"
class="q-mt-sm text-weight-medium"
>
{{ $t('general.status') }}
</div>
<q-select
v-if="$q.screen.lt.md"
id="select-status"
for="select-status"
v-model="currentStatus"
outlined
dense
autocomplete="off"
option-value="value"
option-label="label"
map-options
emit-value
:options="[
{ label: $t('general.all'), value: 'All' },
{ label: $t('status.ACTIVE'), value: 'ACTIVE' },
{ label: $t('status.INACTIVE'), value: 'INACTIVE' },
]"
/>
</span>
</AdvanceSearch>
</template>
</q-input>
<div class="row col-md-5" style="white-space: nowrap">
<q-select
v-show="$q.screen.gt.sm"
ref="refFilter"
v-if="$q.screen.gt.sm"
id="select-status"
for="select-status"
v-model="currentStatus"
@ -2154,16 +2184,16 @@ const emptyCreateDialog = ref(false);
id="form-basic-info-customer"
:onCreate="customerFormState.dialogType === 'create'"
@edit="
(customerFormState.dialogType = 'edit'),
(customerFormState.readonly = false)
((customerFormState.dialogType = 'edit'),
(customerFormState.readonly = false))
"
@cancel="() => customerFormUndo(false)"
@delete="
customerFormState.editCustomerId &&
deleteCustomerById(
customerFormState.editCustomerId,
async () => await fetchListCustomer(true, $q.screen.xs),
)
deleteCustomerById(
customerFormState.editCustomerId,
async () => await fetchListCustomer(true, $q.screen.xs),
)
"
:customer-type="customerFormData.customerType"
v-model:registered-branch-id="customerFormData.registeredBranchId"
@ -4231,16 +4261,16 @@ const emptyCreateDialog = ref(false);
id="form-basic-info-customer"
:onCreate="customerFormState.dialogType === 'create'"
@edit="
(customerFormState.dialogType = 'edit'),
(customerFormState.readonly = false)
((customerFormState.dialogType = 'edit'),
(customerFormState.readonly = false))
"
@cancel="() => customerFormUndo(false)"
@delete="
customerFormState.editCustomerId &&
deleteCustomerById(
customerFormState.editCustomerId,
async () => await fetchListCustomer(true, $q.screen.xs),
)
deleteCustomerById(
customerFormState.editCustomerId,
async () => await fetchListCustomer(true, $q.screen.xs),
)
"
:customer-type="customerFormData.customerType"
v-model:registered-branch-id="customerFormData.registeredBranchId"

View file

@ -113,6 +113,8 @@ const useCustomerStore = defineStore('api-customer', () => {
includeBranch?: boolean;
status?: 'CREATED' | 'ACTIVE' | 'INACTIVE';
customerType?: CustomerType;
startDate?: string;
endDate?: string;
},
Data extends Pagination<
(Customer &

View file

@ -45,6 +45,8 @@ const useEmployeeStore = defineStore('api-employee', () => {
customerId?: string;
customerBranchId?: string;
activeOnly?: boolean;
startDate?: string;
endDate?: string;
payload?: { passport?: string[] };
}) {
const { payload, ...params } = opts || {};