feat: customer employee update & drawer info

This commit is contained in:
puriphatt 2024-06-12 08:40:07 +00:00
parent a61b3e550e
commit 46a7f9ca96
7 changed files with 473 additions and 71 deletions

View file

@ -8,6 +8,7 @@ defineProps<{
addressTitle?: string; addressTitle?: string;
addressTitleEN?: string; addressTitleEN?: string;
noAddress?: boolean; noAddress?: boolean;
noPaddingTab?: boolean;
}>(); }>();
const address = defineModel('address', { default: '' }); const address = defineModel('address', { default: '' });
@ -16,9 +17,36 @@ const provinceId = defineModel<string | null | undefined>('provinceId');
const districtId = defineModel<string | null | undefined>('districtId'); const districtId = defineModel<string | null | undefined>('districtId');
const subDistrictId = defineModel<string | null | undefined>('subDistrictId'); const subDistrictId = defineModel<string | null | undefined>('subDistrictId');
const zipCode = defineModel<string>('zipCode', { default: '' }); const zipCode = defineModel<string>('zipCode', { default: '' });
const employeeTab = defineModel<string>('employeeTab');
const tabsList = defineModel<{ name: string; label: string }[]>('tabsList');
</script> </script>
<template> <template>
<div class="row items-stretch" style="position: absolute; inset: 0"> <div class="column absolute-top" style="inset: 0">
<div
v-if="tabsList && tabsList.length > 0"
class="row surface-2 q-px-md q-pt-md full-width"
style="border-bottom: 1px solid var(--brand-1)"
>
<q-tabs
dense
class="app-text-muted cancel-overflow"
v-model="employeeTab"
active-class="active-tab"
indicator-color="transparent"
>
<q-tab
v-for="tab in tabsList"
v-bind:key="tab.name"
class="content-tab text-capitalize"
:name="tab.name"
:label="$t(tab.label)"
style="z-index: 999"
/>
</q-tabs>
</div>
<div class="row full-width" style="flex: 1">
<div class="col-3" v-if="$slots['person-card']"> <div class="col-3" v-if="$slots['person-card']">
<slot name="person-card"></slot> <slot name="person-card"></slot>
</div> </div>
@ -27,10 +55,11 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
'col-9': $slots['person-card'], 'col-9': $slots['person-card'],
'col-12': !$slots['person-card'], 'col-12': !$slots['person-card'],
}" }"
style="position: relative" class="relative-position"
> >
<AppBox <AppBox
bordered bordered
:noPadding="noPaddingTab"
:class="{ :class="{
'q-my-md q-mr-md': $slots['person-card'], 'q-my-md q-mr-md': $slots['person-card'],
'q-ma-md': !$slots['person-card'], 'q-ma-md': !$slots['person-card'],
@ -65,4 +94,28 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
</AppBox> </AppBox>
</div> </div>
</div> </div>
</div>
</template> </template>
<style scoped lang="scss">
.active-tab {
color: var(--brand-1);
background-color: var(--surface-3);
border-top: 1px solid var(--brand-1);
border-left: 1px solid var(--brand-1);
border-right: 1px solid var(--brand-1);
border-top-left-radius: var(--radius-2);
border-top-right-radius: var(--radius-2);
margin-bottom: -1.5px;
border-bottom: 3px solid var(--surface-3);
}
.content-tab {
border-top-left-radius: var(--radius-2);
border-top-right-radius: var(--radius-2);
position: relative;
}
:deep(.q-tabs__content) {
overflow: visible;
}
</style>

View file

@ -9,7 +9,7 @@ const employerID = defineModel<string>('employerID');
// employee // employee
const customerBranchId = defineModel<string>('customerBranchId'); const customerBranchId = defineModel<string>('customerBranchId');
const employeeID = defineModel<string>('employeeID'); const employeeId = defineModel<string>('employeeId');
const nrcNo = defineModel<string>('nrcNo'); const nrcNo = defineModel<string>('nrcNo');
defineProps<{ defineProps<{
@ -85,6 +85,7 @@ onMounted(async () => {});
id="select-employer-branch" id="select-employer-branch"
use-input use-input
input-debounce="0" input-debounce="0"
:hide-dropdown-icon="readonly"
:dense="dense" :dense="dense"
:outlined="!readonly" :outlined="!readonly"
:readonly="readonly" :readonly="readonly"
@ -113,7 +114,7 @@ onMounted(async () => {});
hide-bottom-space hide-bottom-space
class="col-3" class="col-3"
:label="$t('formDialogEmployeeID')" :label="$t('formDialogEmployeeID')"
v-model="employeeID" v-model="employeeId"
/> />
<q-input <q-input
mask="## #### ###### #" mask="## #### ###### #"

View file

@ -135,7 +135,7 @@ onMounted(async () => {
v-bind:key="index" v-bind:key="index"
:name="`tab${index}`" :name="`tab${index}`"
class="row col-12 items-start" class="row col-12 items-start"
style="overflow: auto; height: 50vh" style="overflow: auto"
> >
<div class="col-3 app-text-muted"> <div class="col-3 app-text-muted">
{{ $t(`formDialogTitleHealthCheck`) }} {{ $t(`formDialogTitleHealthCheck`) }}

View file

@ -107,7 +107,7 @@ onMounted(async () => {
v-bind:key="index" v-bind:key="index"
:name="`tab${index}`" :name="`tab${index}`"
class="row col-12 items-start" class="row col-12 items-start"
style="overflow: auto; height: 50vh" style="overflow: auto"
> >
<div class="col-3 app-text-muted"> {{ $t(`workHistory`) }}</div> <div class="col-3 app-text-muted"> {{ $t(`workHistory`) }}</div>
<div class="col-9 row q-col-gutter-md"> <div class="col-9 row q-col-gutter-md">

View file

@ -145,6 +145,7 @@ function reset() {
style="position: relative" style="position: relative"
:class="{ dark: $q.dark.isActive }" :class="{ dark: $q.dark.isActive }"
> >
<slot></slot>
<slot name="info"></slot> <slot name="info"></slot>
</div> </div>

View file

@ -726,8 +726,6 @@ watch(
> >
<template #info> <template #info>
<InfoForm <InfoForm
:addressTitle="$t('formDialogTitleAddressPure')"
:addressTitleEN="$t('formDialogTitleAddressPure') + ' ENG'"
:readonly="!infoDrawerEdit" :readonly="!infoDrawerEdit"
v-model:address="formData.address" v-model:address="formData.address"
v-model:addressEN="formData.addressEN" v-model:addressEN="formData.addressEN"

View file

@ -35,7 +35,13 @@ import {
CustomerBranchCreate, CustomerBranchCreate,
CustomerType, CustomerType,
} from 'stores/customer/types'; } from 'stores/customer/types';
import { EmployeeCreate, Employee } from 'stores/employee/types'; import {
EmployeeCreate,
Employee,
EmployeeWork,
EmployeeCheckup,
EmployeeOther,
} from 'stores/employee/types';
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import FormPerson from 'src/components/02_personnel-management/FormPerson.vue'; import FormPerson from 'src/components/02_personnel-management/FormPerson.vue';
@ -106,9 +112,13 @@ const fieldSelectedCustomer = ref<{ label: string; value: string }>({
value: 'all', value: 'all',
}); });
const currentEmployee = ref<Employee>();
const isEmployeeEdit = ref(false);
const formDataEmployeeSameAddr = ref(false); const formDataEmployeeSameAddr = ref(false);
const formDataEmployeeTab = ref('personalInfo'); const formDataEmployeeTab = ref('personalInfo');
const employeeOwnerBranchOption = ref(); const infoDrawerEmployee = ref(false);
const infoDrawerEmployeeEdit = ref(false);
const infoEmployeePersonCard = ref();
const formDataEmployee = ref<EmployeeCreate>({ const formDataEmployee = ref<EmployeeCreate>({
image: null, image: null,
customerBranchId: '', customerBranchId: '',
@ -325,12 +335,56 @@ function openDialogCustomerType() {
} }
} }
function openDialogInputForm(action: 'FORM' | 'INFO' = 'FORM', id?: string) { async function openDialogInputForm(
action: 'FORM' | 'INFO' = 'FORM',
id?: string,
) {
if (action === 'INFO') { if (action === 'INFO') {
if (!id) return; if (!id) return;
infoDrawer.value = true; if (selectorLabel.value === 'EMPLOYER') infoDrawer.value = true;
if (selectorLabel.value === 'EMPLOYEE') {
await assignFormDataEmployee(id);
infoDrawerEmployee.value = true;
infoDrawerEmployeeEdit.value = false;
const employee = currentEmployee.value;
infoEmployeePersonCard.value = employee
? [
{
id: employee.id,
img: `${employee.profileImageUrl}`,
name:
locale.value === 'en-US'
? `${employee.firstNameEN} ${employee.lastNameEN}`
: `${employee.firstName} ${employee.lastName}`,
male: employee.gender === 'male',
female: employee.gender === 'female',
badge: employee.code,
disabled: employee.status === 'INACTIVE',
},
]
: [];
const code = currentEmployee.value?.code.split('-')[0];
const result = await fetchListBranch({
includeCustomer: true,
query: code,
pageSize: 30,
});
if (result) {
employeeStore.ownerOption = result.result.map((i) => ({
label: i.code,
value: i.id,
}));
}
}
} else { } else {
dialogInputForm.value = true; if (selectorLabel.value === 'EMPLOYER') dialogInputForm.value = true;
if (selectorLabel.value === 'EMPLOYEE') {
if (!id) return;
await assignFormDataEmployee(id);
dialogEmployee.value = true;
}
} }
} }
@ -390,6 +444,12 @@ function clearForm() {
} }
function clearFormEmployee() { function clearFormEmployee() {
profileUrl.value = null;
profileSubmit.value = false;
dialogEmployee.value = false;
isEmployeeEdit.value = false;
infoDrawerEmployee.value = false;
infoDrawerEmployeeEdit.value = false;
formDataEmployee.value = { formDataEmployee.value = {
image: null, image: null,
customerBranchId: '', customerBranchId: '',
@ -520,15 +580,14 @@ async function onSubmit() {
} }
if (selectorLabel.value === 'EMPLOYEE') { if (selectorLabel.value === 'EMPLOYEE') {
console.log(profileFile.value);
await employeeStore.create({ await employeeStore.create({
...formDataEmployee.value, ...formDataEmployee.value,
image: profileSubmit.value ? profileFile.value ?? null : null, image: profileSubmit.value ? profileFile.value ?? null : null,
}); });
const resultList = await employeeStore.fetchList(); const resultList = await employeeStore.fetchList();
if (resultList) listEmployee.value = resultList.result; if (resultList) listEmployee.value = resultList.result;
clearFormEmployee(); clearFormEmployee();
dialogEmployee.value = false;
} }
} }
@ -582,6 +641,7 @@ async function fetchListCustomer() {
} }
async function onSubmitEdit(id: string) { async function onSubmitEdit(id: string) {
if (selectorLabel.value === 'EMPLOYER') {
if (!formData.value) return; if (!formData.value) return;
const tempValue: CustomerUpdate = { const tempValue: CustomerUpdate = {
@ -597,6 +657,21 @@ async function onSubmitEdit(id: string) {
infoDrawer.value = false; infoDrawer.value = false;
fetchListCustomer(); fetchListCustomer();
clearForm(); clearForm();
}
if (selectorLabel.value === 'EMPLOYEE') {
if (!formDataEmployee.value) return;
await employeeStore.editById(id, {
...formDataEmployee.value,
image: profileSubmit.value ? profileFile.value ?? null : null,
});
const resultList = await employeeStore.fetchList();
if (resultList) listEmployee.value = resultList.result;
clearFormEmployee();
}
} }
async function onDelete(id: string) { async function onDelete(id: string) {
@ -703,6 +778,103 @@ async function assignFormData(data: Customer & { branch: CustomerBranch[] }) {
}); });
} }
async function assignFormDataEmployee(id: string) {
if (!listEmployee.value) return;
const foundEmployee = listEmployee.value.find((x: Employee) => x.id === id);
if (foundEmployee) {
const fetchCheckup = await employeeStore.fetchCheckup(foundEmployee.id);
const fetchWork = await employeeStore.fetchWork(foundEmployee.id);
const fetchOther = await employeeStore.fetchOther(foundEmployee.id);
const employeeCheckup =
fetchCheckup &&
fetchCheckup.map((i: EmployeeCheckup) => ({
coverageExpireDate: i.coverageExpireDate,
coverageStartDate: i.coverageStartDate,
insuranceCompany: i.insuranceCompany,
medicalBenefitScheme: i.medicalBenefitScheme,
remark: i.remark,
hospitalName: i.hospitalName,
provinceId: i.provinceId,
checkupResult: i.checkupResult,
checkupType: i.checkupType,
}));
const employeeWork =
fetchWork &&
fetchWork.map((i: EmployeeWork) => ({
workEndDate: i.workEndDate,
workPermitExpireDate: i.workPermitExpireDate,
workPermitIssuDate: i.workPermitIssuDate,
workPermitNo: i.workPermitNo,
workplace: i.workplace,
jobType: i.jobType,
positionName: i.positionName,
ownerName: i.ownerName,
remark: i.remark,
}));
const employeeOther = fetchOther && {
motherBirthPlace: fetchOther.motherBirthPlace,
motherLastNameEN: fetchOther.motherLastNameEN,
motherFirstNameEN: fetchOther.motherFirstNameEN,
fatherLastNameEN: fetchOther.fatherLastNameEN,
fatherFirstNameEN: fetchOther.fatherFirstNameEN,
motherLastName: fetchOther.motherLastName,
motherFirstName: fetchOther.motherFirstName,
fatherLastName: fetchOther.fatherLastName,
fatherFirstName: fetchOther.fatherFirstName,
fatherBirthPlace: fetchOther.fatherBirthPlace,
citizenId: fetchOther.citizenId,
};
currentEmployee.value = foundEmployee;
profileUrl.value = foundEmployee.profileImageUrl;
profileSubmit.value = true;
isEmployeeEdit.value = true;
formDataEmployee.value = {
image: foundEmployee.profileImageUrl,
customerBranchId: foundEmployee.customerBranchId,
nrcNo: foundEmployee.nrcNo,
dateOfBirth: foundEmployee.dateOfBirth,
gender: foundEmployee.gender,
nationality: foundEmployee.nationality,
firstName: foundEmployee.firstName,
firstNameEN: foundEmployee.firstNameEN,
lastName: foundEmployee.lastName,
lastNameEN: foundEmployee.lastNameEN,
addressEN: foundEmployee.addressEN,
address: foundEmployee.address,
zipCode: foundEmployee.zipCode,
passportType: foundEmployee.passportType,
passportNumber: foundEmployee.passportNumber,
passportIssueDate: foundEmployee.passportIssueDate,
passportExpiryDate: foundEmployee.passportExpiryDate,
passportIssuingCountry: foundEmployee.passportIssuingCountry,
passportIssuingPlace: foundEmployee.passportIssuingPlace,
previousPassportReference: foundEmployee.previousPassportReference,
visaType: foundEmployee.visaType,
visaNumber: foundEmployee.visaNumber,
visaIssueDate: foundEmployee.visaIssueDate,
visaExpiryDate: foundEmployee.visaExpiryDate,
visaIssuingPlace: foundEmployee.visaIssuingPlace,
visaStayUntilDate: foundEmployee.visaStayUntilDate,
tm6Number: foundEmployee.tm6Number,
entryDate: foundEmployee.entryDate,
workerStatus: foundEmployee.workerStatus,
subDistrictId: foundEmployee.subDistrictId,
districtId: foundEmployee.districtId,
provinceId: foundEmployee.provinceId,
employeeWork: employeeWork,
employeeCheckup: employeeCheckup,
employeeOtherInfo: employeeOther,
};
}
}
onMounted(async () => { onMounted(async () => {
const resultStats = await getStatsCustomer(); const resultStats = await getStatsCustomer();
@ -737,7 +909,6 @@ onMounted(async () => {
const resultOption = await fetch('/option/option.json'); const resultOption = await fetch('/option/option.json');
employeeStore.globalOption = await resultOption.json(); employeeStore.globalOption = await resultOption.json();
console.log(employeeStore.globalOption);
}); });
watch(locale, () => { watch(locale, () => {
@ -1028,6 +1199,8 @@ watch(fieldSelectedCustomer, async () => {
], ],
})) || [] })) || []
" "
@update-card="openDialogInputForm"
@enter-card="openDialogInputForm"
@delete-card="onDelete" @delete-card="onDelete"
/> />
</div> </div>
@ -1291,10 +1464,16 @@ watch(fieldSelectedCustomer, async () => {
:title="$t('customerEmployeeAdd')" :title="$t('customerEmployeeAdd')"
:submit=" :submit="
() => { () => {
onSubmit(); isEmployeeEdit
? currentEmployee && onSubmitEdit(currentEmployee.id)
: onSubmit();
}
"
:close="
() => {
clearFormEmployee();
} }
" "
:close="() => {}"
> >
<template #prepend> <template #prepend>
<ProfileUpload <ProfileUpload
@ -2041,6 +2220,176 @@ watch(fieldSelectedCustomer, async () => {
</InfoForm> </InfoForm>
</template> </template>
</DrawerInfo> </DrawerInfo>
<!-- Employee Info -->
<DrawerInfo
:title="
currentEmployee
? $i18n.locale === 'en-US'
? `${currentEmployee.firstNameEN} ${currentEmployee.lastNameEN}`
: `${currentEmployee.firstName} ${currentEmployee.lastName}`
: '-'
"
v-model:drawer-open="infoDrawerEmployee"
:is-edit="infoDrawerEmployeeEdit"
:editData="() => (infoDrawerEmployeeEdit = true)"
:undo="() => (infoDrawerEmployeeEdit = false)"
:close="() => clearFormEmployee()"
:submit="
() => {
currentEmployee && onSubmitEdit(currentEmployee.id);
}
"
>
<InfoForm
v-if="employeeStore.globalOption"
:readonly="!infoDrawerEmployeeEdit"
:noAddress="formDataEmployeeTab !== 'personalInfo'"
:noPaddingTab="
formDataEmployeeTab === 'healthCheck' ||
formDataEmployeeTab === 'workHistory'
"
v-model:tabs-list="employeeTab"
v-model:employee-tab="formDataEmployeeTab"
v-model:address="formDataEmployee.address"
v-model:addressEN="formDataEmployee.addressEN"
v-model:provinceId="formDataEmployee.provinceId"
v-model:districtId="formDataEmployee.districtId"
v-model:subDistrictId="formDataEmployee.subDistrictId"
v-model:zipCode="formDataEmployee.zipCode"
>
<template #person-card>
<div class="q-ma-md">
<AppBox class="surface-1" style="padding: 0">
<PersonCard
no-hover
no-action
no-detail
no-bg
:list="infoEmployeePersonCard"
:gridColumns="1"
/>
</AppBox>
</div>
</template>
<template #information>
<BasicInformation
v-if="formDataEmployeeTab === 'personalInfo' && currentEmployee"
employee
dense
outlined
separator
:readonly="!infoDrawerEmployeeEdit"
:employee-owner-option="employeeStore.ownerOption"
v-model:customer-branch-id="formDataEmployee.customerBranchId"
v-model:employee-id="currentEmployee.code"
v-model:nrc-no="formDataEmployee.nrcNo"
@filter-owner-branch="employeeFilterOwnerBranch"
/>
</template>
<template #person>
<FormPerson
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
employee
separator
:readonly="!infoDrawerEmployeeEdit"
v-model:firstName="formDataEmployee.firstName"
v-model:lastName="formDataEmployee.lastName"
v-model:firstNameEN="formDataEmployee.firstNameEN"
v-model:lastNameEN="formDataEmployee.lastNameEN"
v-model:gender="formDataEmployee.gender"
v-model:birthDate="formDataEmployee.dateOfBirth"
v-model:nationality="formDataEmployee.nationality"
/>
<FormEmployeeHealthCheck
v-if="
formDataEmployeeTab === 'healthCheck' &&
formDataEmployee.employeeCheckup
"
:readonly="!infoDrawerEmployeeEdit"
dense
outlined
v-model:employee-checkup="formDataEmployee.employeeCheckup"
v-model:checkup-type-option="
employeeStore.globalOption.tha.nationality
"
v-model:medical-benefit-option="
employeeStore.globalOption.tha.typeInsurance
"
v-model:insurance-company-option="
employeeStore.globalOption.tha.insurancePlace
"
/>
<FormEmployeeWorkHistory
v-if="formDataEmployeeTab === 'workHistory'"
dense
outlined
:readonly="!infoDrawerEmployeeEdit"
v-model:employee-work="formDataEmployee.employeeWork"
v-model:position-name-option="employeeStore.globalOption.tha.position"
v-model:job-type-option="employeeStore.globalOption.tha.businessType"
v-model:workplace-option="employeeStore.globalOption.tha.area"
/>
<FormEmployeeOther
v-if="
formDataEmployeeTab === 'other' &&
formDataEmployee.employeeOtherInfo
"
:readonly="!infoDrawerEmployeeEdit"
dense
outlined
v-model:employee-other="formDataEmployee.employeeOtherInfo"
/>
</template>
<template #by-type>
<FormEmployeePassport
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
employee
separator
:readonly="!infoDrawerEmployeeEdit"
v-model:passport-type="formDataEmployee.passportType"
v-model:passport-number="formDataEmployee.passportNumber"
v-model:passport-issue-date="formDataEmployee.passportIssueDate"
v-model:passport-expiry-date="formDataEmployee.passportExpiryDate"
v-model:passport-issuing-place="formDataEmployee.passportIssuingPlace"
v-model:passport-issuing-country="
formDataEmployee.passportIssuingCountry
"
v-model:previous-passport-reference="
formDataEmployee.previousPassportReference
"
v-model:passport-type-option="
employeeStore.globalOption.tha.nationality
"
v-model:passport-issuing-country-option="
employeeStore.globalOption.tha.nationality
"
/>
<FormEmployeeVisa
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
employee
:readonly="!infoDrawerEmployeeEdit"
v-model:visa-type="formDataEmployee.visaType"
v-model:visa-number="formDataEmployee.visaNumber"
v-model:visa-issue-date="formDataEmployee.visaIssueDate"
v-model:visa-expiry-date="formDataEmployee.visaExpiryDate"
v-model:visa-issuing-place="formDataEmployee.visaIssuingPlace"
v-model:visa-stay-until-date="formDataEmployee.visaStayUntilDate"
v-model:tm6-number="formDataEmployee.tm6Number"
v-model:entry-date="formDataEmployee.entryDate"
v-model:visa-type-option="employeeStore.globalOption.tha.nationality"
/>
</template>
</InfoForm>
</DrawerInfo>
</template> </template>
<style scoped> <style scoped>