feat(wip): customer(employee) branch

This commit is contained in:
Methapon2001 2024-08-09 15:09:46 +07:00
parent 622b25b900
commit e853f6bf91
4 changed files with 341 additions and 36 deletions

View file

@ -8,15 +8,31 @@ import useOptionStore from 'stores/options';
import { Status } from 'stores/types';
import { CustomerBranch, CustomerType } from 'stores/customer/types';
import SideMenu from 'components/SideMenu.vue';
import { DialogFormContainer, DialogHeader } from 'components/dialog';
import BranchCardCustomer from 'components/03_customer-management/BranchCardCustomer.vue';
import PaginationComponent from 'components/PaginationComponent.vue';
import NoData from 'components/NoData.vue';
import { QTableProps } from 'quasar';
import { AddressForm } from 'components/form';
import { useCustomerBranchForm } from './form';
import { storeToRefs } from 'pinia';
import { SaveButton, CancelButton, UndoButton } from 'components/button';
import {
EmployerFormAbout,
EmployerFormBusiness,
EmployerFormContact,
} from './components';
const flowStore = useFlowStore();
const userCustomer = useCustomerStore();
const { fetchListCustomeBranch } = userCustomer;
const customerStore = useCustomerStore();
const { fetchListCustomeBranch } = customerStore;
const customerBranchFormStore = useCustomerBranchForm();
const {
currentFormData: customerBranchFormData,
state: customerBranchFormState,
} = storeToRefs(customerBranchFormStore);
const inputSearch = ref<string>('');
@ -136,19 +152,10 @@ watch([inputSearch, currentStatus], async () => {
<template>
<div
class="row justify-between bordered-b surface-3 full-width"
class="row justify-between bordered-b surface-3 full-width q-px-md"
style="z-index: 1"
>
<div class="row items-center col-12 col-md">
<q-btn
round
icon="mdi-arrow-left"
flat
dense
@click="$emit('back')"
class="q-mr-md"
/>
<q-card-section
class="q-pa-sm q-pt-md q-mr-md q-mb-sm"
:class="{
@ -179,9 +186,7 @@ watch([inputSearch, currentStatus], async () => {
</div>
</div>
<div
class="row items-center justify-end q-px-md col-12 col-sm q-py-sm no-wrap"
>
<div class="row items-center justify-end col-12 col-sm q-py-sm no-wrap">
<q-input
lazy-rules="ondemand"
outlined
@ -388,7 +393,12 @@ watch([inputSearch, currentStatus], async () => {
dense
round
flat
@click="$emit('viewDetail', props.row, props.rowIndex)"
@click="
() => {
customerBranchFormStore.initForm('info', props.row.id);
customerBranchFormState.dialogModal = true;
}
"
/>
</q-td>
</q-tr>
@ -445,6 +455,172 @@ watch([inputSearch, currentStatus], async () => {
/>
</div>
</div>
<DialogFormContainer
:model-value="customerBranchFormState.dialogModal"
:on-close="() => (customerBranchFormState.dialogModal = false)"
@submit="() => {}"
>
<template #header>
<DialogHeader
:title="
$t(`form.title.${customerBranchFormState.dialogType}`, {
name: $t('customer.employee'),
})
"
/>
</template>
<div
style="flex: 1; width: 100%; overflow-y: auto"
class="surface-2 q-pa-lg"
id="customer-form"
>
<div class="col surface-1 full-height rounded bordered row">
<div
class="col full-height"
style="max-height: 100%; overflow-y: auto"
v-if="$q.screen.gt.sm"
>
<div class="q-py-md q-pl-md q-pr-sm">
<SideMenu
:menu="[
{
name: $t('customer.form.group.basicInfo'),
anchor: 'form-basic-info-customer',
},
{
name: $t('customer.form.group.branch'),
anchor: 'form-branch-customer-branch',
},
]"
background="transparent"
:active="{
background: 'hsla(var(--blue-6-hsl) / .2)',
foreground: 'var(--blue-6)',
}"
scroll-element="#customer-form-content"
/>
</div>
</div>
<div
class="col-12 col-md-10 q-py-md q-pr-md q-pl-sm full-height scroll"
>
<div class="row q-col-gutter-sm q-mb-sm">
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
size="xs"
class="q-pa-sm rounded q-mr-sm"
color="info"
name="mdi-office-building-outline"
style="background-color: var(--surface-3)"
/>
<span>{{ $t('customerBranch.tab.main') }}</span>
</div>
</div>
<EmployerFormAbout
class="q-mb-xl"
:readonly="customerBranchFormState.dialogType === 'info'"
v-model:id="customerBranchFormData.id"
v-model:branch-no="customerBranchFormData.branchNo"
v-model:tax-no="customerBranchFormData.taxNo"
v-model:code="customerBranchFormData.code"
v-model:name="customerBranchFormData.name"
v-model:name-en="customerBranchFormData.nameEN"
v-model:registered-name="customerBranchFormData.registerName"
v-model:registered-date="customerBranchFormData.registerDate"
v-model:authorized-capital="
customerBranchFormData.authorizedCapital
"
/>
<div class="row q-col-gutter-sm q-mb-sm">
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
size="xs"
class="q-pa-sm rounded q-mr-sm"
color="info"
name="mdi-office-building-outline"
style="background-color: var(--surface-3)"
/>
<span>{{ $t('customerBranch.tab.address') }}</span>
</div>
</div>
<AddressForm
prefix-id="employer-branch"
class="q-mb-xl"
hide-title
dense
:readonly="customerBranchFormState.dialogType === 'info'"
outlined
:title="$t('form.address')"
v-model:address="customerBranchFormData.address"
v-model:addressEN="customerBranchFormData.addressEN"
v-model:province-id="customerBranchFormData.provinceId"
v-model:district-id="customerBranchFormData.districtId"
v-model:sub-district-id="customerBranchFormData.subDistrictId"
:addressTitle="$t('form.address')"
:addressTitleEN="$t('form.address', { suffix: '(EN)' })"
/>
<div class="row q-col-gutter-sm q-mb-sm">
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
size="xs"
class="q-pa-sm rounded q-mr-sm"
color="info"
name="mdi-office-building-outline"
style="background-color: var(--surface-3)"
/>
<span>{{ $t('customerBranch.tab.business') }}</span>
</div>
</div>
<EmployerFormBusiness
dense
class="q-mb-lg"
outlined
prefix-id="employer-branch"
:readonly="customerBranchFormState.dialogType === 'info'"
v-model:employment-office="customerBranchFormData.employmentOffice"
v-model:bussiness-type="customerBranchFormData.bussinessType"
v-model:bussiness-type-en="customerBranchFormData.bussinessTypeEN"
v-model:job-position="customerBranchFormData.jobPosition"
v-model:job-position-en="customerBranchFormData.jobPositionEN"
v-model:job-description="customerBranchFormData.jobDescription"
v-model:sale-employee="customerBranchFormData.saleEmployee"
v-model:pay-date="customerBranchFormData.payDate"
v-model:wage-rate="customerBranchFormData.wageRate"
/>
<div class="row q-col-gutter-sm q-mb-sm">
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
size="xs"
class="q-pa-sm rounded q-mr-sm"
color="info"
name="mdi-office-building-outline"
style="background-color: var(--surface-3)"
/>
<span>{{ $t('customerBranch.tab.contact') }}</span>
</div>
</div>
<EmployerFormContact
class="q-mb-lg"
:readonly="customerBranchFormState.dialogType === 'info'"
v-model:email="customerBranchFormData.email"
v-model:telephone="customerBranchFormData.telephoneNo"
/>
</div>
</div>
</div>
<template #footer>
<CancelButton outlined class="q-ml-auto" />
<SaveButton solid class="q-ml-sm" />
</template>
</DialogFormContainer>
</template>
<style scoped>

View file

@ -15,6 +15,7 @@ import { Status } from 'stores/types';
import { CustomerStats, Customer, CustomerBranch } from 'stores/customer/types';
import { Employee, EmployeeHistory } from 'stores/employee/types';
import { AddressForm } from 'components/form';
import DrawerInfo from 'components/DrawerInfo.vue';
import ButtonAddComponent from 'components/ButtonAddCompoent.vue';
import PersonCard from 'components/shared/PersonCard.vue';
@ -23,18 +24,14 @@ import TooltipComponent from 'components/TooltipComponent.vue';
import EmptyAddButton from 'components/AddButton.vue';
import NoData from 'components/NoData.vue';
import PaginationComponent from 'components/PaginationComponent.vue';
import DialogForm from 'components/DialogForm.vue';
import SideMenu from 'components/SideMenu.vue';
import BasicInformation from 'components/03_customer-management/employee/BasicInformation.vue';
import FormPerson from 'components/02_personnel-management/FormPerson.vue';
import {
EmployerFormBasicInfo,
EmployerFormBranch,
EmployerBranch,
} from './components';
import { AddressForm } from 'components/form';
import { EmployerFormBasicInfo, EmployerFormBranch } from './components';
import BranchPage from './BranchPage.vue';
import FormEmployeePassport from 'components/03_customer-management/FormEmployeePassport.vue';
import FormEmployeeVisa from 'components/03_customer-management/FormEmployeeVisa.vue';
import DialogForm from 'components/DialogForm.vue';
import SideMenu from 'components/SideMenu.vue';
import { AddButton } from 'components/button';
import {
@ -655,8 +652,8 @@ watch(
? customerStats.map((v) => ({
count:
v.name === 'CORP'
? (statsCustomerType?.CORP ?? 0)
: (statsCustomerType?.PERS ?? 0),
? statsCustomerType?.CORP ?? 0
: statsCustomerType?.PERS ?? 0,
label:
v.name === 'CORP'
? 'customerLegalEntity'
@ -1668,7 +1665,7 @@ watch(
{
icon: 'mdi-clock-outline',
value: props.row.dateOfBirth
? (calculateAge(props.row.dateOfBirth) ?? '')
? calculateAge(props.row.dateOfBirth) ?? ''
: '',
},
],
@ -1800,19 +1797,17 @@ watch(
</div>
</div>
<div class="col column" v-if="$route.name === 'CustomerBranchManagement'">
<EmployerBranch
<div
class="col column rounded bordered"
style="overflow: hidden"
v-if="$route.name === 'CustomerBranchManagement'"
>
<BranchPage
v-if="currentCustomer"
:customer-id="currentCustomer.id"
:customer-type="currentCustomer.customerType"
v-model:mode-view="gridView"
@back="$router.push('/customer-management')"
@view-detail="
async (value) => {
await fetchListOfOptionBranch();
// TODO: Assign data to form
}
"
v-model:branch="branch"
v-model:current-customer-name="currentCustomer.customerName"
v-model:current-customer-url-image="currentCustomer.imageUrl"

View file

@ -1,5 +1,5 @@
export { default as EmployerBranch } from './employer/EmployerBranch.vue';
export { default as EmployerFormBasicInfo } from './employer/EmployerFormBasicInfo.vue';
export { default as EmployerFormBranch } from './employer/EmployerFormBranch.vue';
export { default as EmployerFormBusiness } from './employer/EmployerFormBusiness.vue';
export { default as EmployerFormContact } from './employer/EmployerFormContact.vue';
export { default as EmployerFormAbout } from './employer/EmployerFormAbout.vue';

View file

@ -232,6 +232,140 @@ export const useCustomerForm = defineStore('form-customer', () => {
};
});
export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
const customerStore = useCustomerStore();
const defaultFormData: CustomerBranchCreate = {
id: '',
code: '',
branchNo: 1,
address: '',
addressEN: '',
provinceId: '',
districtId: '',
subDistrictId: '',
zipCode: '',
email: '',
telephoneNo: '',
name: '',
status: 'CREATED',
taxNo: '',
nameEN: '',
legalPersonNo: '',
registerName: '',
registerDate: new Date(),
authorizedCapital: '',
employmentOffice: '',
bussinessType: '',
bussinessTypeEN: '',
jobPosition: '',
jobPositionEN: '',
jobDescription: '',
saleEmployee: '',
payDate: new Date(),
wageRate: 0,
};
let resetFormData = structuredClone(defaultFormData);
const currentFormData = ref<CustomerBranchCreate>(
structuredClone(defaultFormData),
);
const state = ref<{
dialogType: 'info' | 'create' | 'edit';
dialogOpen: boolean;
dialogModal: boolean;
currentCustomerId: string;
}>({
dialogType: 'info',
dialogOpen: false,
dialogModal: false,
currentCustomerId: '',
});
async function initForm(form: 'create'): Promise<void>;
async function initForm(form: 'info' | 'edit', id: string): Promise<void>;
async function initForm(form: 'info' | 'create' | 'edit', id?: string) {
state.value.dialogType = form;
resetFormData = structuredClone(defaultFormData);
if (!id) return;
const _data = await customerStore.getBranchById(id);
if (!_data) return;
resetFormData = {
id: _data.id,
code: _data.code,
branchNo: _data.branchNo,
address: _data.address,
addressEN: _data.addressEN,
provinceId: _data.provinceId,
districtId: _data.districtId,
subDistrictId: _data.subDistrictId,
zipCode: _data.zipCode,
email: _data.email,
telephoneNo: _data.telephoneNo,
name: _data.name,
status: undefined,
taxNo: _data.taxNo,
nameEN: _data.nameEN,
legalPersonNo: _data.legalPersonNo,
registerName: _data.registerName,
registerDate: new Date(_data.registerDate),
authorizedCapital: _data.authorizedCapital,
employmentOffice: _data.employmentOffice,
bussinessType: _data.bussinessType,
bussinessTypeEN: _data.bussinessTypeEN,
jobPosition: _data.jobPosition,
jobPositionEN: _data.jobPositionEN,
jobDescription: _data.jobDescription,
saleEmployee: _data.saleEmployee,
payDate: new Date(_data.payDate),
wageRate: _data.wageRate,
};
currentFormData.value = structuredClone(resetFormData);
}
function isFormDataDifferent() {
return (
JSON.stringify(resetFormData) !== JSON.stringify(currentFormData.value)
);
}
async function submitForm() {
if (!state.value.currentCustomerId) {
throw new Error(
'Employer id cannot be found. Did you properly set employer id?',
);
}
if (!currentFormData.value.id) {
await customerStore.createBranch({
...currentFormData.value,
customerId: state.value.currentCustomerId,
});
} else {
await customerStore.editBranchById(currentFormData.value.id, {
...currentFormData.value,
id: undefined,
});
}
}
return {
state,
initForm,
currentFormData,
isFormDataDifferent,
submitForm,
};
});
export const useEmployeeForm = defineStore('form-employee', () => {
const customerStore = useCustomerStore();
const employeeStore = useEmployeeStore();