jws-frontend/src/pages/03_customer-management/MainPage.vue
2024-08-02 09:25:05 +07:00

4511 lines
143 KiB
Vue

<script setup lang="ts">
import { computed, ref, watch, toRaw } from 'vue';
import { useQuasar, type QTableProps } from 'quasar';
import { storeToRefs } from 'pinia';
import { getUserId, getRole } from 'src/services/keycloak';
import { Status } from 'src/stores/types';
import useCustomerStore from 'src/stores/customer';
import useEmployeeStore from 'src/stores/employee';
import useOptionStore from 'src/stores/options';
import useMyBranchStore from 'src/stores/my-branch';
import ButtonAddComponent from 'src/components/ButtonAddCompoent.vue';
import PersonCard from 'components/home/PersonCard.vue';
import UsersDetailCardComponent from 'src/components/UsersDetailCardComponent.vue';
import StatCardComponent from 'components/StatCardComponent.vue';
import TooltipComponent from 'components/TooltipComponent.vue';
import AddButton from 'components/AddButton.vue';
import AppBox from 'components/app/AppBox.vue';
import ItemCard from 'src/components/ItemCard.vue';
import FormDialog from 'src/components/FormDialog.vue';
import ProfileUpload from 'src/components/ProfileUpload.vue';
import BasicInformation from 'src/components/03_customer-management/BasicInformation.vue';
import TabComponent from 'src/components/TabComponent.vue';
import FormAddress from 'src/components/02_personnel-management/FormAddress.vue';
import AboutComponent from 'src/components/03_customer-management/AboutComponent.vue';
import ContactComponent from 'src/components/03_customer-management/ContactInformation.vue';
import OtherInformation from 'src/components/03_customer-management/OtherInformation.vue';
import FormBusiness from 'src/components/03_customer-management/FormBusiness.vue';
import DrawerInfo from 'src/components/DrawerInfo.vue';
import InfoForm from 'src/components/02_personnel-management/InfoForm.vue';
import CustomerInfoComponent from 'src/components/03_customer-management/CustomerInfoComponent.vue';
import NoData from 'components/NoData.vue';
import HistoryEditComponent from 'src/components/03_customer-management/HistoryEditComponent.vue';
import PaginationComponent from 'src/components/PaginationComponent.vue';
import {
CustomerCreate,
CustomerStats,
Customer,
CustomerUpdate,
CustomerBranch,
CustomerType,
} from 'stores/customer/types';
import {
EmployeeCreate,
Employee,
EmployeeWork,
EmployeeCheckup,
EmployeeHistory,
} from 'stores/employee/types';
import { onMounted } from 'vue';
import FormPerson from 'src/components/02_personnel-management/FormPerson.vue';
import FormEmployeeHealthCheck from 'src/components/03_customer-management/FormEmployeeHealthCheck.vue';
import FormEmployeeWorkHistory from 'src/components/03_customer-management/FormEmployeeWorkHistory.vue';
import FormEmployeeOther from 'src/components/03_customer-management/FormEmployeeOther.vue';
import FormEmployeePassport from 'src/components/03_customer-management/FormEmployeePassport.vue';
import FormEmployeeVisa from 'src/components/03_customer-management/FormEmployeeVisa.vue';
import useUtilsStore, { dialog } from 'src/stores/utils';
import { calculateAge, dateFormat } from 'src/utils/datetime';
import { useI18n } from 'vue-i18n';
import useFlowStore from 'src/stores/flow';
const $q = useQuasar();
const { t, locale } = useI18n();
const utilsStore = useUtilsStore();
const userCustomer = useCustomerStore();
const userBranchStore = useMyBranchStore();
const { currentMyBranch } = storeToRefs(userBranchStore);
const columnsEmployee = [
{
name: 'firstName',
align: 'left',
label: 'nameEmployee',
field: 'firstName',
sortable: true,
},
{
name: 'formDialogInputNationality',
align: 'left',
label: 'formDialogInputNationality',
field: 'nationality',
},
{
name: 'formDialogInputPassportNo',
align: 'left',
label: 'formDialogInputPassportNo',
field: 'passportNumber',
},
{
name: 'formDialogInputAge',
align: 'left',
label: 'formDialogInputAge',
field: 'dateOfBirth',
},
{
name: 'passportExpiryDate',
align: 'left',
label: 'passportExpire',
field: 'passportExpiryDate',
},
{
name: 'formDialogEmployeeNRCNo',
align: 'left',
label: 'formDialogEmployeeNRCNo',
field: 'nrcNo',
},
{
name: 'branchLabel',
align: 'left',
label: 'branchLabel',
field: 'customerBranch',
},
{
name: 'type',
align: 'left',
label: 'type',
field: 'type',
sortable: true,
},
{
name: 'action',
label: '',
field: 'action',
},
] satisfies QTableProps['columns'];
const columnsCustomer = [
{
name: 'customerName',
align: 'left',
label: 'corporation',
field: 'customerName',
sortable: true,
},
{
name: 'type',
align: 'left',
label: 'type',
field: 'customerType',
sortable: true,
},
{
name: 'personName',
align: 'left',
label: 'name',
field: 'personName',
},
{
name: 'telephoneNo',
align: 'left',
label: 'telephone',
field: 'branch[0].telephoneNo',
},
{
name: 'branchEmail',
align: 'left',
label: 'formDialogInputEmail',
field: 'branch[0].email',
},
] satisfies QTableProps['columns'];
const {
create,
getStatsCustomer,
fetchList,
editById,
fetchListById,
createBranch,
editBranchById,
fetchListCustomeBranch,
fetchListCustomeBranchById,
} = userCustomer;
const flowStore = useFlowStore();
const employeeStore = useEmployeeStore();
const optionStore = useOptionStore();
const currentTab = ref('employer');
const formData = ref<CustomerCreate>({
status: 'CREATED',
personName: '',
customerType: 'CORP',
customerName: '',
customerNameEN: '',
taxNo: '',
registeredBranchId: currentMyBranch.value?.id || '',
customerBranch: [
{
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,
},
],
image: null,
});
const inputSearch = ref<string>();
const fieldSelectedCustomer = ref<{ label: string; value: string }>({
label: t('all'),
value: 'all',
});
const fieldDisplayEmployer = ref<
{
label: string;
value: string;
}[]
>([
{
label: 'corporation',
value: 'customerName',
},
{
label: 'type',
value: 'type',
},
{
label: 'name',
value: 'personName',
},
{
label: 'telephone',
value: 'telephoneNo',
},
{
label: 'formDialogInputEmail',
value: 'branchEmail',
},
]);
const fieldDisplayEmployee = ref<
{
label: string;
value: string;
}[]
>([
{
label: 'nameEmployee',
value: 'firstName',
},
{
label: 'formDialogInputNationality',
value: 'formDialogInputNationality',
},
{
label: 'formDialogInputPassportNo',
value: 'formDialogInputPassportNo',
},
{
label: 'formDialogInputAge',
value: 'formDialogInputAge',
},
{
label: 'passportExpire',
value: 'passportExpiryDate',
},
{
label: 'formDialogEmployeeNRCNo',
value: 'formDialogEmployeeNRCNo',
},
{
label: 'branchLabel',
value: 'branchLabel',
},
{
label: 'type',
value: 'type',
},
]);
const fieldSelected = ref<
(
| 'customerName'
| 'type'
| 'personName'
| 'telephoneNo'
| 'branchEmail'
| 'firstName'
| 'formDialogInputNationality'
| 'formDialogInputPassportNo'
| 'passportExpiryDate'
| 'formDialogEmployeeNRCNo'
| 'formDialogInputAge'
| 'branchLabel'
| 'action'
)[]
>([
'customerName',
'personName',
'telephoneNo',
'branchEmail',
'firstName',
'formDialogInputNationality',
'formDialogInputPassportNo',
'passportExpiryDate',
'type',
'formDialogEmployeeNRCNo',
'formDialogInputAge',
'branchLabel',
'action',
]);
const splitterModel = ref(15);
const modeView = ref(false);
const currentEmployee = ref<Employee | undefined>();
const currentEmployeeCode = ref('');
const isEmployeeEdit = ref(false);
const formDataEmployeeSameAddr = ref(true);
const formDataEmployeeTab = ref('personalInfo');
const infoDrawerEmployee = ref(false);
const infoDrawerEmployeeEdit = ref(false);
const infoEmployeePersonCard = ref<
{
id: string;
img: string;
name: string;
male: boolean;
female: boolean;
badge: string;
disabled: boolean;
}[]
>();
const statsEmployee = ref(0);
const statsEmployeeGender = ref<{ male: number; female: number }>({
male: 0,
female: 0,
});
const formDataEmployeeOwner = ref<{
id: string;
address: string;
addressEN: string;
provinceId: string;
districtId: string;
subDistrictId: string;
zipCode: string;
}>();
const currentEmployeeId = ref<string>('');
const formDataEmployee = ref<EmployeeCreate>({
code: '',
image: null,
customerBranchId: '',
nrcNo: '',
dateOfBirth: null,
gender: '',
nationality: '',
firstName: '',
firstNameEN: '',
lastName: '',
lastNameEN: '',
addressEN: '',
address: '',
zipCode: '',
passportType: '',
passportNumber: '',
passportIssueDate: null,
passportExpiryDate: null,
passportIssuingCountry: '',
passportIssuingPlace: '',
previousPassportReference: '',
visaType: '',
visaNumber: '',
visaIssueDate: null,
visaExpiryDate: null,
visaIssuingPlace: '',
visaStayUntilDate: null,
tm6Number: '',
entryDate: null,
workerStatus: '',
subDistrictId: '',
districtId: '',
provinceId: '',
employeeWork: [
{
workEndDate: null,
workPermitExpireDate: null,
workPermitIssuDate: null,
workPermitNo: '',
workplace: '',
jobType: '',
positionName: '',
ownerName: '',
remark: '',
},
],
employeeCheckup: [
{
coverageExpireDate: null,
coverageStartDate: null,
insuranceCompany: '',
medicalBenefitScheme: '',
remark: '',
hospitalName: '',
provinceId: '',
checkupResult: '',
checkupType: '',
},
],
employeeOtherInfo: {
citizenId: '',
fatherFirstName: '',
fatherLastName: '',
fatherFirstNameEN: '',
fatherLastNameEN: '',
fatherBirthPlace: '',
motherFirstName: '',
motherLastName: '',
motherFirstNameEN: '',
motherLastNameEN: '',
motherBirthPlace: '',
},
});
const hideStat = ref(false);
const branchOption = ref<{ id: string; name: string }[]>();
const indexTab = ref<number>(0);
const statusToggle = ref<boolean>(false);
const profileSubmit = ref<boolean>(false);
const profileFile = ref<File | undefined>(undefined);
const profileUrl = ref<string | null>('');
const infoDrawer = ref(false);
const infoDrawerEdit = ref(false);
const isMainPage = ref<boolean>(true);
const statsCustomerType = ref<CustomerStats>({
CORP: 0,
PERS: 0,
});
const hideTab = ref<boolean>(true);
const hideBranch = ref<boolean>(true);
const currentCustomerId = ref<string>('');
const dialogInputCustomerBranchForm = ref<boolean>(false);
const currentCustomer = ref<Customer>();
const statBranchNo = ref<number>(0);
const currentBranch = ref<{ name: string; code: string }>({
name: '',
code: '',
});
const branch = ref<CustomerBranch[]>();
const currentPageCustomer = ref<number>(1);
const maxPageCustomer = ref<number>(1);
const pageSize = ref<number>(10);
const currentPageEmployee = ref<number>(1);
const maxPageEmployee = ref<number>(1);
const currentBranchId = ref<string>('');
const currentCustomerName = ref<string>('');
const currentCustomerUrlImage = ref<string | null>(null);
const genderSelector = ref<string>('');
const totalCustomer = ref<number>(0);
const currentStatus = ref<Status | 'All'>('All');
const inputFile = (() => {
const element = document.createElement('input');
element.type = 'file';
element.accept = 'image/*';
const reader = new FileReader();
reader.addEventListener('load', () => {
if (typeof reader.result === 'string') profileUrl.value = reader.result;
if (infoDrawerEdit.value && currentCustomer.value)
currentCustomer.value.imageUrl = profileUrl.value as string;
if (infoDrawerEmployeeEdit.value && infoEmployeePersonCard.value)
infoEmployeePersonCard.value[0].img = profileUrl.value as string;
});
element.addEventListener('change', () => {
profileFile.value = element.files?.[0];
if (profileFile.value) {
reader.readAsDataURL(profileFile.value);
}
});
return element;
})();
const listCustomer = ref<(Customer & { branch: CustomerBranch[] })[]>([]);
const listEmployee = ref<Employee[]>([]);
const itemCard = [
{
icon: 'mdi:office-building',
text: 'customerLegalEntity',
color: 'var(--purple-8)',
},
{
icon: 'heroicons:user-solid',
text: 'customerNaturalPerson',
color: 'var(--green-9)',
},
];
const customerStats = [
{
id: 1,
count: 2,
name: 'CORP',
},
{
id: 2,
count: 3,
name: 'PERS',
},
];
const employeeTab = [
{
name: 'personalInfo',
label: 'personalInfo',
},
{
name: 'healthCheck',
label: 'healthCheck',
},
{
name: 'workHistory',
label: 'workHistory',
},
{
name: 'other',
label: 'other',
},
];
const fieldCustomer = ref([
'all',
'customerLegalEntity',
'customerNaturalPerson',
]);
const countStartsOne = ref<number>(1);
const dialogCustomerType = ref<boolean>(false);
const dialogInputForm = ref<boolean>(false);
const dialogEmployee = ref<boolean>(false);
const infoDrawerBranch = ref<boolean>(false);
const selectorLabel = ref<string>('EMPLOYER');
const selectorList = computed(() => [
{
label: 'EMPLOYER',
count:
(statsCustomerType.value?.CORP ?? 0) +
(statsCustomerType.value?.PERS ?? 0),
},
{
label: 'EMPLOYEE',
count: statsEmployee.value ?? 0,
},
]);
const customerType = ref<CustomerType>('CORP');
const employeeHistoryDialog = ref(false);
const employeeHistory = ref<EmployeeHistory[]>();
async function triggerCreate(type: CustomerType) {
countStartsOne.value = 1;
customerType.value = type;
await fetchListOfOptionBranch();
openDialogInputForm();
dialogCustomerType.value = false;
}
function openDialogCustomerType() {
if (selectorLabel.value === 'EMPLOYER') {
dialogCustomerType.value = true;
}
if (selectorLabel.value === 'EMPLOYEE') {
dialogEmployee.value = true;
}
}
async function openDialogInputForm(
action: 'FORM' | 'INFO' = 'FORM',
id?: string,
isPersonEdit: boolean = false,
) {
if (action === 'INFO') {
if (!id) return;
if (selectorLabel.value === 'EMPLOYER') {
await fetchListOfOptionBranch();
infoDrawer.value = true;
}
if (selectorLabel.value === 'EMPLOYEE') {
await assignFormDataEmployee(id);
infoDrawerEmployee.value = true;
infoDrawerEmployeeEdit.value = isPersonEdit ? true : 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 fetchListCustomeBranch({
includeCustomer: true,
query: code,
pageSize: 30,
});
if (result) employeeStore.ownerOption = result.result;
}
} else {
if (selectorLabel.value === 'EMPLOYER') {
await fetchListOfOptionBranch();
dialogInputForm.value = true;
}
if (selectorLabel.value === 'EMPLOYEE') {
if (!id) return;
await assignFormDataEmployee(id);
const code = currentEmployee.value?.code.split('-')[0];
const result = await fetchListCustomeBranch({
includeCustomer: true,
query: code,
pageSize: 30,
});
if (result) employeeStore.ownerOption = result.result;
dialogEmployee.value = true;
}
}
}
function onClose() {
infoDrawer.value = false;
infoDrawerEdit.value = false;
dialogInputForm.value = false;
flowStore.rotate();
clearForm();
}
function onCloseBranch() {
infoDrawerBranch.value = false;
infoDrawerEdit.value = false;
dialogInputForm.value = false;
flowStore.rotate();
clearForm();
}
function clearForm() {
inputFile.value = '';
profileFile.value = undefined;
profileUrl.value = null;
hideBranch.value = true;
dialogInputForm.value = false;
formData.value = {
status: 'CREATED',
customerType: 'CORP',
customerName: '',
customerNameEN: '',
personName: '',
taxNo: '',
registeredBranchId: currentMyBranch.value?.id || '',
customerBranch: [
{
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,
},
],
image: null,
};
}
function clearFormEmployee() {
hideTab.value = true;
inputFile.value = '';
profileUrl.value = null;
profileSubmit.value = false;
dialogEmployee.value = false;
isEmployeeEdit.value = false;
infoDrawerEmployee.value = false;
infoDrawerEmployeeEdit.value = false;
formDataEmployeeSameAddr.value = true;
currentEmployeeCode.value = '';
formDataEmployeeTab.value = 'personalInfo';
currentEmployee.value = undefined;
formDataEmployeeOwner.value = undefined;
formDataEmployee.value = {
code: '',
image: null,
customerBranchId: '',
nrcNo: '',
dateOfBirth: null,
gender: '',
nationality: '',
firstName: '',
firstNameEN: '',
lastName: '',
lastNameEN: '',
addressEN: '',
address: '',
zipCode: '',
passportType: '',
passportNumber: '',
passportIssueDate: null,
passportExpiryDate: null,
passportIssuingCountry: '',
passportIssuingPlace: '',
previousPassportReference: '',
visaType: '',
visaNumber: '',
visaIssueDate: null,
visaExpiryDate: null,
visaIssuingPlace: '',
visaStayUntilDate: null,
tm6Number: '',
entryDate: null,
workerStatus: '',
subDistrictId: '',
districtId: '',
provinceId: '',
employeeWork: [
{
workEndDate: null,
workPermitExpireDate: null,
workPermitIssuDate: null,
workPermitNo: '',
workplace: '',
jobType: '',
positionName: '',
ownerName: '',
remark: '',
},
],
employeeCheckup: [
{
coverageExpireDate: null,
coverageStartDate: null,
insuranceCompany: '',
medicalBenefitScheme: '',
remark: '',
hospitalName: '',
provinceId: '',
checkupResult: '',
checkupType: '',
},
],
employeeOtherInfo: {
citizenId: '',
fatherFirstName: '',
fatherLastName: '',
fatherFirstNameEN: '',
fatherLastNameEN: '',
fatherBirthPlace: '',
motherFirstName: '',
motherLastName: '',
motherFirstNameEN: '',
motherLastNameEN: '',
motherBirthPlace: '',
},
};
}
function deleteCustomerById(id: string) {
dialog({
color: 'negative',
icon: 'mdi-alert',
title: t('deleteConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('deleteConfirmMessage'),
action: async () => {
await userCustomer.deleteById(id);
const resultList = await fetchList({ includeBranch: true });
if (resultList) listCustomer.value = resultList.result;
infoDrawer.value = false;
flowStore.rotate();
},
cancel: () => {},
});
}
function deleteBranchId(id: string) {
dialog({
color: 'negative',
icon: 'mdi-alert',
title: t('deleteConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('deleteConfirmMessage'),
action: async () => {
await userCustomer.deleteBranchById(id);
const result = await fetchListById(currentCustomerId.value);
if (result) branch.value = result.branch;
infoDrawerBranch.value = false;
flowStore.rotate();
},
cancel: () => {},
});
}
// async function onSubmit() {
// if (selectorLabel.value === 'EMPLOYER') {
// await create({
// ...formData.value,
// customerType: customerType.value === 'CORP' ? 'CORP' : 'PERS',
// image: profileSubmit.value ? profileFile.value ?? null : null,
// });
// clearForm();
// const resultList = await fetchList({ includeBranch: true });
// if (resultList) listCustomer.value = resultList.result;
// }
// if (selectorLabel.value === 'EMPLOYEE') {
// await employeeStore.create({
// ...formDataEmployee.value,
// image: profileSubmit.value ? profileFile.value ?? null : null,
// });
// const resultList = await employeeStore.fetchList();
// if (resultList) listEmployee.value = resultList.result;
// const resultStatsEmployee = await employeeStore.getStatsEmployee();
// if (resultStatsEmployee) statsEmployee.value = resultStatsEmployee;
// clearFormEmployee();
// }
// flowStore.rotate();
// }
async function deleteByIdCheckOrwork(
id: string,
type: 'healthCheck' | 'workHistory',
indexTab: number,
) {
dialog({
color: 'info',
icon: 'mdi-alert',
title: t('saveConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('saveConfirmMessage'),
action: async () => {
if (type === 'healthCheck') {
await employeeStore.deleteByIdCheckUp({
employeeId: currentEmployeeId.value,
checkUpId: id,
});
formDataEmployee.value.employeeCheckup?.splice(indexTab, 1);
}
if (type === 'workHistory') {
await employeeStore.deleteByIdWork({
employeeId: currentEmployeeId.value,
workId: id,
});
formDataEmployee.value.employeeWork?.splice(indexTab, 1);
}
flowStore.rotate();
},
cancel: () => {},
});
}
async function onSubmitEmployee(
type: 'personalInfo' | 'healthCheck' | 'workHistory' | 'other',
indexTab: number = 0,
) {
dialog({
color: 'info',
icon: 'mdi-alert',
title: t('saveConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('saveConfirmMessage'),
action: async () => {
if (type === 'personalInfo') {
const res = await employeeStore.create({
...formDataEmployee.value,
employeeWork: [],
employeeCheckup: [],
employeeOtherInfo: {},
image: profileSubmit.value ? profileFile.value ?? null : null,
});
if (res) {
currentEmployeeId.value = res.id;
hideTab.value = false;
}
const resultList = await employeeStore.fetchList();
if (resultList) {
listEmployee.value = resultList.result;
}
const resultStatsEmployee = await employeeStore.getStatsEmployee();
if (resultStatsEmployee) statsEmployee.value = resultStatsEmployee;
}
if (
formDataEmployee.value.employeeCheckup?.[indexTab] &&
type === 'healthCheck'
) {
const res = await employeeStore.createEmployeeCheckup(
currentEmployeeId.value,
{
...formDataEmployee.value.employeeCheckup[indexTab],
},
);
if (res) {
formDataEmployee.value.employeeCheckup[indexTab].id = res.id;
formDataEmployee.value.employeeCheckup[indexTab].statusSave = true;
}
}
if (
formDataEmployee.value.employeeWork?.[indexTab] &&
type === 'workHistory'
) {
const res = await employeeStore.createEmployeeWork(
currentEmployeeId.value,
{
...formDataEmployee.value.employeeWork[indexTab],
},
);
if (res) {
formDataEmployee.value.employeeWork[indexTab].id = res.id;
formDataEmployee.value.employeeWork[indexTab].statusSave = true;
}
}
if (formDataEmployee.value.employeeOtherInfo && type === 'other') {
const res = await employeeStore.createEmployeeOtherInfo(
currentEmployeeId.value,
{
...formDataEmployee.value.employeeOtherInfo,
},
);
}
flowStore.rotate();
},
cancel: () => {},
});
}
async function onSubmitBasicInformation() {
if (selectorLabel.value === 'EMPLOYER') {
dialog({
color: 'info',
icon: 'mdi-alert',
title: t('saveConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('saveConfirmMessage'),
action: async () => {
const res = await create({
...formData.value,
customerBranch: [],
customerType: customerType.value === 'CORP' ? 'CORP' : 'PERS',
image: profileSubmit.value ? profileFile.value ?? null : null,
});
if (res) {
currentCustomerId.value = res.id;
hideBranch.value = false;
}
const resultList = await fetchList({ includeBranch: true });
if (resultList) listCustomer.value = resultList.result;
},
cancel: () => {},
});
}
flowStore.rotate();
}
async function onSubmitCustomerBranch(opt: { isClearForm: boolean }) {
dialog({
color: 'info',
icon: 'mdi-alert',
title: t('saveConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('saveConfirmMessage'),
action: async () => {
if (
formData.value.customerBranch !== undefined &&
formData.value.customerBranch[indexTab.value] !== undefined
) {
await createBranch({
...formData.value.customerBranch[indexTab.value],
customerId: currentCustomerId.value,
});
}
},
cancel: () => {},
});
if (opt.isClearForm) {
dialogInputCustomerBranchForm.value = false;
clearForm();
}
const result = await fetchListById(currentCustomerId.value);
if (result) {
currentCustomerName.value = result.customerName;
currentCustomerUrlImage.value = result.imageUrl;
branch.value = result.branch;
statBranchNo.value = result.branch.length;
}
flowStore.rotate();
}
async function fetchListOfOptionBranch() {
const uid = getUserId();
const role = getRole();
if (!uid) return;
if (role?.includes('system')) {
const result = await userBranchStore.fetchListOptionBranch();
if (result && result.total > 0) branchOption.value = result.result;
} else {
const result = await userBranchStore.fetchListMyBranch(uid);
if (result && result.total > 0) branchOption.value = result.result;
}
formData.value.registeredBranchId = currentMyBranch.value?.id || '';
}
async function fetchListCustomer() {
const resultList = await fetchList({
includeBranch: true,
page: currentPageCustomer.value,
pageSize: pageSize.value,
status:
currentStatus.value === 'All'
? undefined
: currentStatus.value === 'ACTIVE'
? 'ACTIVE'
: 'INACTIVE',
query: inputSearch.value,
});
if (resultList) {
currentPageCustomer.value = resultList.page;
maxPageCustomer.value = Math.ceil(resultList.total / pageSize.value);
listCustomer.value = resultList.result;
}
}
async function fetchListEmployee() {
const resultListEmployee = await employeeStore.fetchList({
page: currentPageEmployee.value,
pageSize: pageSize.value,
status:
currentStatus.value === 'All'
? undefined
: currentStatus.value === 'ACTIVE'
? 'ACTIVE'
: 'INACTIVE',
query: inputSearch.value,
gender: genderSelector.value,
});
if (resultListEmployee) {
maxPageEmployee.value = Math.ceil(
resultListEmployee.total / pageSize.value,
);
listEmployee.value = resultListEmployee.result;
}
}
async function triggerChangeStatus(id: string, status: string) {
return await new Promise((resolve, reject) => {
dialog({
color: status !== 'INACTIVE' ? 'warning' : 'info',
icon: status !== 'INACTIVE' ? 'mdi-alert' : 'mdi-comment-alert',
title: t('confirmChangeStatusTitle'),
actionText:
status !== 'INACTIVE' ? t('switchOffLabel') : t('switchOnLabel'),
message:
status !== 'INACTIVE'
? t('confirmChangeStatusOffMessage')
: t('confirmChangeStatusOnMessage'),
action: async () => {
if (currentTab.value === 'employee') {
await toggleStatusEmployee(id, status === 'ACTIVE' ? true : false)
.then(resolve)
.catch(reject);
} else {
await toggleStatusCustomer(id, status === 'ACTIVE' ? true : false)
.then(resolve)
.catch(reject);
}
},
cancel: () => {},
});
});
}
async function toggleStatusEmployee(id: string, status: boolean) {
await employeeStore.editById(id, { status: !status ? 'ACTIVE' : 'INACTIVE' });
await fetchListEmployee();
flowStore.rotate();
}
async function toggleStatusCustomer(id: string, status: boolean) {
await editById(id, { status: !status ? 'ACTIVE' : 'INACTIVE' });
await fetchListCustomer();
flowStore.rotate();
}
async function onSubmitEdit(id: string) {
if (selectorLabel.value === 'EMPLOYER') {
if (!formData.value) return;
const tempValue: CustomerUpdate = {
registeredBranchId: formData.value.registeredBranchId,
status: formData.value.status,
customerType: formData.value.customerType,
customerName: formData.value.customerName,
customerNameEN: formData.value.customerNameEN,
customerBranch: formData.value.customerBranch,
taxNo: formData.value.taxNo,
personName: formData.value.personName,
image: profileFile.value,
};
if (tempValue.status === 'CREATED') delete tempValue['status'];
await editById(id, tempValue);
infoDrawer.value = false;
fetchListCustomer();
clearForm();
}
if (selectorLabel.value === 'EMPLOYEE') {
const isOk = await checkEmployeeForm();
if (isOk) {
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();
}
}
flowStore.rotate();
}
async function onDelete(id: string) {
if (!id) return;
dialog({
color: 'negative',
icon: 'mdi-alert',
title: t('deleteConfirmTitle'),
actionText: t('ok'),
persistent: true,
message: t('deleteConfirmMessage'),
action: async () => {
await employeeStore.deleteById(id);
const resultList = await employeeStore.fetchList();
if (resultList) listEmployee.value = resultList.result;
clearFormEmployee();
flowStore.rotate();
},
cancel: () => {},
});
}
async function submitBranch() {
if (formData.value.customerBranch?.[indexTab.value]) {
delete formData.value.customerBranch[indexTab.value]['id'];
formData.value.customerBranch[indexTab.value].status = statusToggle.value
? 'ACTIVE'
: 'INACTIVE';
await editBranchById(currentBranchId.value, {
...formData.value.customerBranch[indexTab.value],
customerId: currentCustomerId.value,
});
const result = await fetchListById(currentCustomerId.value);
if (result) {
branch.value = result.branch;
}
}
infoDrawerBranch.value = false;
flowStore.rotate();
clearForm();
}
function undo() {
if (selectorLabel.value === 'EMPLOYER') {
formData.value = {
...prevCustomer.value,
};
infoDrawerEdit.value = false;
}
if (selectorLabel.value === 'EMPLOYEE') {
if (!currentEmployee.value) return;
infoDrawerEmployeeEdit.value = false;
assignFormDataEmployee(currentEmployee.value.id);
}
}
async function employeeFilterOwnerBranch(
val: string,
update: (...args: unknown[]) => void,
) {
update(async () => {
const result = await fetchListCustomeBranch({
includeCustomer: true,
query: val,
pageSize: 30,
});
if (result) employeeStore.ownerOption = result.result;
});
}
const prevCustomer = ref<CustomerCreate>({
status: 'CREATED',
customerType: 'CORP',
customerName: '',
customerNameEN: '',
personName: '',
taxNo: '',
customerBranch: [],
image: null,
registeredBranchId: '',
});
async function assignFormData(
customerId: string,
branch?: CustomerBranch,
tabNo: number = 0,
) {
let data;
const res = await fetchListById(customerId);
if (res) {
data = res;
}
if (!data) return;
indexTab.value = tabNo;
countStartsOne.value = 1;
prevCustomer.value = {
registeredBranchId: data.registeredBranchId,
status: data.status,
customerType: data.customerType,
customerName: data.customerName,
customerNameEN: data.customerNameEN,
personName: data.personName,
taxNo: data.taxNo,
customerBranch: [],
image: null,
};
data.branch.forEach((v) => {
prevCustomer.value.customerBranch?.push({
code: v.code,
branchNo: v.branchNo,
id: v.id,
address: v.address,
addressEN: v.addressEN,
provinceId: v.province.id,
districtId: v.district.id,
subDistrictId: v.subDistrict.id,
zipCode: v.zipCode,
email: v.email,
telephoneNo: v.telephoneNo,
name: v.name,
status: undefined,
taxNo: v.taxNo,
nameEN: v.nameEN,
legalPersonNo: v.legalPersonNo,
registerName: v.registerName,
registerDate: new Date(v.registerDate),
authorizedCapital: v.authorizedCapital,
employmentOffice: v.employmentOffice,
bussinessType: v.bussinessType,
bussinessTypeEN: v.bussinessTypeEN,
jobPosition: v.jobPosition,
jobPositionEN: v.jobPositionEN,
jobDescription: v.jobDescription,
saleEmployee: v.saleEmployee,
payDate: new Date(v.payDate),
wageRate: v.wageRate,
});
});
cloneData();
if (formData.value.customerBranch?.length === 0) {
formData.value.customerBranch?.push({
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,
});
}
}
function cloneData() {
formData.value = {
...prevCustomer.value,
customerBranch: structuredClone(toRaw(prevCustomer.value.customerBranch)),
};
}
async function assignFormDataEmployee(id: string) {
if (!listEmployee.value) return;
currentEmployeeId.value = id;
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,
};
currentEmployeeCode.value = foundEmployee.code;
currentEmployee.value = foundEmployee;
profileUrl.value = foundEmployee.profileImageUrl;
foundEmployee.profileImageUrl
? (profileSubmit.value = true)
: (profileSubmit.value = false);
isEmployeeEdit.value = true;
const foundBranch = await fetchListCustomeBranchById(
foundEmployee.customerBranchId,
);
formDataEmployeeOwner.value = {
id: foundBranch.id,
address: foundBranch.address,
addressEN: foundBranch.addressEN,
provinceId: foundBranch.provinceId,
districtId: foundBranch.districtId,
subDistrictId: foundBranch.subDistrictId,
zipCode: foundBranch.zipCode,
};
formDataEmployee.value = {
code: foundEmployee.code,
image: null,
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,
};
if (foundBranch.address === foundEmployee.address) {
formDataEmployeeSameAddr.value = true;
} else {
formDataEmployeeSameAddr.value = false;
}
if (infoEmployeePersonCard.value) {
infoEmployeePersonCard.value[0].img = foundEmployee.profileImageUrl || '';
}
}
flowStore.rotate();
}
async function checkEmployeeForm() {
const formData = formDataEmployee.value;
let forget = false;
for (const [key, val] of Object.entries(formData)) {
if (key === 'workerStatus') continue;
if (key === 'image') continue;
const validPersonalInfoKeys = [
'customerBranchId',
'firstName',
'firstNameEN',
'lastName',
'lastNameEN',
'dateOfBirth',
'gender',
'nationality',
'passportType',
'passportNumber',
'passportIssueDate',
'passportExpiryDate',
'passportIssuingCountry',
'passportIssuingPlace',
];
if (validPersonalInfoKeys.includes(key) && (val === '' || val === null)) {
formDataEmployeeTab.value = 'personalInfo';
return;
}
if (val === '' || val === null) {
forget = true;
}
}
if (forget) {
return await new Promise((resolve) => {
dialog({
color: 'warning',
icon: 'mdi-alert',
title: t('warning'),
actionText: t('ok'),
persistent: true,
message: t('warningForgetInput'),
action: () => {
resolve(true);
},
cancel: () => {
resolve(false);
},
});
});
} else return true;
}
async function openHistory(id: string) {
const res = await employeeStore.getEditHistory(id);
employeeHistory.value = res.reverse();
employeeHistoryDialog.value = true;
}
async function fetchListStatsEmployeeGender() {
const resultStatsEmployeeGender = await employeeStore.getStatsEmployeeGender({
query: inputSearch.value,
status:
currentStatus.value === 'All'
? undefined
: currentStatus.value === 'ACTIVE'
? 'ACTIVE'
: 'INACTIVE',
});
if (resultStatsEmployeeGender) {
if (genderSelector.value === 'male') {
statsEmployeeGender.value.male = resultStatsEmployeeGender.male;
return;
}
if (genderSelector.value === 'female') {
statsEmployeeGender.value.female = resultStatsEmployeeGender.female;
return;
}
statsEmployeeGender.value = resultStatsEmployeeGender;
}
}
onMounted(async () => {
utilsStore.currentTitle.title = 'customerManagement';
utilsStore.currentTitle.path = [
{
text: 'customerManagementCaption',
handler: () => {
isMainPage.value = true;
currentCustomerUrlImage.value = null;
clearForm();
},
},
];
modeView.value = $q.screen.lt.md ? true : false;
const resultStats = await getStatsCustomer();
const resultList = await fetchList({
includeBranch: true,
page: 1,
pageSize: pageSize.value,
});
if (resultStats) {
statsCustomerType.value = resultStats;
}
if (resultList) listCustomer.value = resultList.result;
if (
(statsCustomerType.value?.CORP ?? 0) +
(statsCustomerType.value?.PERS ?? 0) >
0
) {
selectorLabel.value = 'EMPLOYER';
}
if (resultList) {
currentPageCustomer.value = resultList.page;
maxPageCustomer.value = Math.ceil(resultList.total / pageSize.value);
listCustomer.value = resultList.result;
}
const resultStatsEmployee = await employeeStore.getStatsEmployee();
if (resultStatsEmployee) statsEmployee.value = resultStatsEmployee;
await fetchListStatsEmployeeGender();
const resultListEmployee = await employeeStore.fetchList({
page: 1,
pageSize: pageSize.value,
});
if (resultListEmployee) {
maxPageEmployee.value = Math.ceil(
resultListEmployee.total / pageSize.value,
);
listEmployee.value = resultListEmployee.result;
}
flowStore.rotate();
});
watch(locale, () => {
fieldSelectedCustomer.value = {
label: `${fieldSelectedCustomer.value.label}`,
value: fieldSelectedCustomer.value?.value,
};
});
watch(fieldSelectedCustomer, async () => {
let resultList;
if (fieldSelectedCustomer.value.value === 'all') {
resultList = await fetchList({ includeBranch: true });
}
if (fieldSelectedCustomer.value.value === 'customerLegalEntity') {
resultList = await fetchList({ includeBranch: true, customerType: 'CORP' });
}
if (fieldSelectedCustomer.value.value === 'customerNaturalPerson') {
resultList = await fetchList({ includeBranch: true, customerType: 'PERS' });
}
if (resultList) {
listCustomer.value = resultList.result;
}
flowStore.rotate();
});
watch(
() => formDataEmployeeOwner.value,
(e) => {
if (!e) return;
if (formDataEmployeeSameAddr.value) {
formDataEmployee.value.address = e.address;
formDataEmployee.value.addressEN = e.addressEN;
formDataEmployee.value.provinceId = e.provinceId;
formDataEmployee.value.districtId = e.districtId;
formDataEmployee.value.subDistrictId = e.subDistrictId;
formDataEmployee.value.zipCode = e.zipCode;
}
formDataEmployee.value.customerBranchId = e.id;
},
);
watch(
() => formDataEmployeeSameAddr.value,
(isSame) => {
if (!formDataEmployeeOwner.value) return;
if (isSame) {
formDataEmployee.value.address = formDataEmployeeOwner.value.address;
formDataEmployee.value.addressEN = formDataEmployeeOwner.value.addressEN;
formDataEmployee.value.provinceId =
formDataEmployeeOwner.value.provinceId;
formDataEmployee.value.districtId =
formDataEmployeeOwner.value.districtId;
formDataEmployee.value.subDistrictId =
formDataEmployeeOwner.value.subDistrictId;
formDataEmployee.value.zipCode = formDataEmployeeOwner.value.zipCode;
}
formDataEmployee.value.customerBranchId = formDataEmployeeOwner.value.id;
},
);
watch(genderSelector, async () => {
await fetchListEmployee();
await fetchListStatsEmployeeGender();
flowStore.rotate();
});
watch(selectorLabel, async () => {
if (inputSearch.value) inputSearch.value = undefined;
if (selectorLabel.value === 'EMPLOYEE') {
await fetchListEmployee();
await fetchListStatsEmployeeGender();
} else {
await fetchListCustomer();
}
});
watch([inputSearch, currentStatus], async () => {
if (selectorLabel.value === 'EMPLOYEE') {
currentPageEmployee.value = 1;
await fetchListEmployee();
await fetchListStatsEmployeeGender();
} else {
currentPageCustomer.value = 1;
await fetchListCustomer();
}
flowStore.rotate();
});
watch(
() => $q.screen.lt.md,
(v) => {
if (v) modeView.value = true;
},
);
watch(isMainPage, () => {
const tmp: typeof utilsStore.currentTitle.path = [
{
text: 'customerManagementCaption',
handler: () => {
isMainPage.value = true;
currentCustomerUrlImage.value = null;
clearForm();
},
},
];
if (isMainPage.value === false) {
tmp.push({
text: currentCustomerName.value || '',
});
}
utilsStore.currentTitle.path = tmp;
});
</script>
<template>
<ButtonAddComponent style="z-index: 999">
<div v-if="isMainPage">
<q-fab-action
v-if="selectorLabel === 'EMPLOYER' || !selectorLabel"
id="add-customer-legal-entity"
style="color: white; background-color: hsla(var(--violet-11-hsl))"
@click="triggerCreate('CORP')"
padding="xs"
icon="mdi-office-building"
:label="$t('add') + ' ' + $t('customerLegalEntity')"
external-label
label-position="left"
/>
<q-fab-action
v-if="selectorLabel === 'EMPLOYER' || !selectorLabel"
id="add-customer-natural-person"
:label="$t('add') + ' ' + $t('customerNaturalPerson')"
external-label
label-position="left"
@click="triggerCreate('PERS')"
style="color: white; background-color: hsla(var(--teal-10-hsl))"
padding="xs"
icon="mdi-account-plus"
/>
<q-fab-action
v-if="selectorLabel === 'EMPLOYEE' || !selectorLabel"
:label="$t('add') + ' ' + $t('EMPLOYEE')"
external-label
id="add-employee"
label-position="left"
@click="openDialogCustomerType()"
color="primary"
padding="xs"
icon="mdi-account-plus"
/>
</div>
<div v-else>
<q-fab-action
id="add-branch"
:style="`color: white; background-color: ${customerType === 'CORP' ? 'hsla(var(--violet-11-hsl))' : 'hsla(var(--pink-6-hsl))'}`"
@click="
() => {
indexTab = 0;
console.log(statBranchNo);
dialogInputCustomerBranchForm = true;
}
"
padding="xs"
icon="mdi-office-building"
:label="$t('formDialogTitleCreateSubBranch')"
external-label
label-position="left"
/>
</div>
</ButtonAddComponent>
<div class="column full-height no-wrap">
<div v-if="isMainPage" class="column full-height">
<div class="text-body-2 text-weight-medium q-mb-xs flex items-center">
{{ $t('dataSum') }}
<q-badge
v-if="listCustomer"
rounded
class="q-ml-sm"
style="
background-color: hsla(var(--info-bg) / 0.15);
color: hsl(var(--info-bg));
"
>
{{
selectorLabel === 'EMPLOYER'
? listCustomer?.length
: listEmployee.length
}}
</q-badge>
<q-btn
class="q-ml-sm"
icon="mdi-pin"
color="primary"
size="sm"
flat
dense
rounded
@click="hideStat = !hideStat"
:style="hideStat ? 'rotate: 90deg' : ''"
style="transition: 0.1s ease-in-out"
/>
</div>
<div class="row full-width">
<!-- stat -->
<transition name="slide">
<div v-if="!hideStat" class="col-12 q-mb-md">
<div class="scroll">
<StatCardComponent
v-if="customerStats"
labelI18n
:branch="
customerStats &&
(selectorLabel === 'EMPLOYER'
? customerStats.map((v) => ({
count:
v.name === 'CORP'
? statsCustomerType?.CORP ?? 0
: statsCustomerType?.PERS ?? 0,
label:
v.name === 'CORP'
? 'customerLegalEntity'
: 'customerNaturalPerson',
icon:
v.name === 'CORP'
? 'mdi-office-building'
: 'mdi-account',
color: v.name === 'CORP' ? 'purple' : 'green',
}))
: [
{
label: 'EMPLOYEE',
count: statsEmployee,
icon: 'mdi-account',
color: 'pink',
},
])
"
:dark="$q.dark.isActive"
/>
</div>
</div>
</transition>
</div>
<!-- main -->
<div
class="surface-2 bordered rounded col column full-width"
style="overflow: hidden"
>
<!-- tabs -->
<div class="column">
<div
class="row q-px-md q-py-sm justify-between full-width surface-3 bordered-b"
>
<q-input
lazy-rules="ondemand"
for="input-search"
outlined
dense
:label="$t('search')"
class="col-12 col-md-3"
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="inputSearch"
debounce="200"
>
<template #prepend>
<q-icon name="mdi-magnify" />
</template>
</q-input>
<div
class="row col-md-5 col-12"
:class="{ 'q-pt-xs': $q.screen.lt.md }"
style="white-space: nowrap"
>
<q-select
lazy-rules="ondemand"
id="select-status"
for="select-status"
v-model="currentStatus"
outlined
dense
option-value="value"
option-label="label"
class="col"
:class="{ 'offset-md-5': modeView }"
map-options
emit-value
:hide-dropdown-icon="$q.screen.lt.sm"
:options="[
{ label: $t('all'), value: 'All' },
{ label: $t('statusACTIVE'), value: 'ACTIVE' },
{ label: $t('statusINACTIVE'), value: 'INACTIVE' },
]"
></q-select>
<q-select
lazy-rules="ondemand"
id="select-field"
v-if="modeView === false"
for="select-field"
class="q-ml-sm col"
:options="
currentTab === 'employer'
? fieldDisplayEmployer
: fieldDisplayEmployee
"
:display-value="$t('displayField')"
:hide-dropdown-icon="$q.screen.lt.sm"
v-model="fieldSelected"
:option-label="(l) => $t(l.label)"
option-value="value"
map-options
emit-value
outlined
multiple
dense
/>
<q-btn-toggle
id="btn-mode"
v-model="modeView"
dense
class="no-shadow bordered rounded surface-1 q-ml-sm"
:toggle-color="$q.dark.isActive ? 'grey-9' : 'grey-2'"
size="xs"
:options="[
{ value: true, slot: 'folder' },
{ value: false, slot: 'list' },
]"
>
<template v-slot:folder>
<q-icon
id="icon-mode-grid"
name="mdi-view-grid-outline"
size="16px"
class="q-px-sm q-py-xs rounded"
:style="{
color: $q.dark.isActive
? modeView
? '#C9D3DB '
: '#787B7C'
: modeView
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
<template v-slot:list>
<q-icon
id="icon-mode-list"
name="mdi-format-list-bulleted"
class="q-px-sm q-py-xs rounded"
size="16px"
:style="{
color: $q.dark.isActive
? modeView === false
? '#C9D3DB'
: '#787B7C'
: modeView === false
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
</div>
<div class="surface-2 bordered-b q-px-md">
<q-tabs
dense
v-model="currentTab"
align="left"
class="full-height"
active-color="info"
>
<q-tab
name="employer"
id="tab-employer"
@click="
async () => {
selectorLabel = 'EMPLOYER';
currentPageCustomer = 1;
inputSearch = '';
currentStatus = 'All';
flowStore.rotate();
}
"
>
<div
class="row"
:class="
currentTab === 'employer' ? 'text-bold' : 'app-text-muted'
"
>
{{ $t('EMPLOYER') }}
</div>
</q-tab>
<q-tab
name="employee"
id="tab-employee"
@click="
async () => {
selectorLabel = 'EMPLOYEE';
currentPageEmployee = 1;
inputSearch = '';
currentStatus = 'All';
flowStore.rotate();
}
"
>
<div
class="row"
:class="
currentTab === 'employee' ? 'text-bold' : 'app-text-muted'
"
>
{{ $t('EMPLOYEE') }}
</div>
</q-tab>
</q-tabs>
</div>
</div>
<!-- body -->
<q-splitter
v-model="splitterModel"
:limits="[0, 100]"
class="col full-width"
before-class="overflow-hidden"
after-class="overflow-hidden"
>
<template v-slot:before>
<div
class="column q-pa-md surface-1 full-height full-width"
style="gap: var(--size-1)"
>
<template v-if="selectorLabel === 'EMPLOYER'">
<q-item
v-close-popup
clickable
v-for="v in fieldCustomer"
:key="v"
dense
class="no-padding items-center rounded full-width"
active-class="employer-active"
:active="fieldSelectedCustomer.value === v"
@click="fieldSelectedCustomer = { label: v, value: v }"
>
<span class="q-px-md ellipsis">
{{ $t(v) }}
</span>
</q-item>
</template>
<template v-else>
<q-item
active
dense
active-class="employer-active"
class="no-padding items-center rounded full-width"
v-close-popup
clickable
>
<span class="q-px-md ellipsis">
{{ $t('totalEmployee') }}
</span>
</q-item>
</template>
</div>
</template>
<template v-slot:after>
<div class="column full-height no-wrap">
<!-- employer -->
<template
v-if="
listCustomer &&
statsCustomerType.PERS + statsCustomerType.CORP > 0 &&
selectorLabel === 'EMPLOYER'
"
>
<div
v-if="listCustomer.length === 0"
class="row col full-width items-center justify-center"
style="min-height: 250px"
>
<NoData :not-found="!!inputSearch" />
</div>
<div
v-if="listCustomer.length !== 0"
class="col q-pa-md scroll full-width"
>
<q-table
flat
bordered
:grid="modeView"
:rows="listCustomer"
:columns="columnsCustomer"
class="full-width"
card-container-class="q-col-gutter-md"
row-key="name"
:rows-per-page-options="[0]"
hide-pagination
:visible-columns="fieldSelected"
>
<template v-slot:header="props">
<q-tr
style="background-color: hsla(var(--info-bg) / 0.07)"
:props="props"
>
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
{{ $t(col.label) }}
</q-th>
<q-th auto-width />
</q-tr>
</template>
<template v-slot:body="props">
<q-tr
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
'status-active': props.row.status !== 'INACTIVE',
'status-inactive': props.row.status === 'INACTIVE',
}"
:id="`row-table-${props.row.customerName}`"
:props="props"
@click="
() => {
currentCustomerName = props.row.customerName;
customerType = props.row.customerType;
currentCustomerUrlImage = props.row.imageUrl;
currentCustomerId = props.row.id;
const { branch, ...payload } = props.row;
currentCustomer = payload;
statBranchNo =
branch[branch.length - 1].branchNo + 1;
isMainPage = false;
}
"
>
<q-td v-if="fieldSelected.includes('customerName')">
<div class="row items-center">
<div
style="
width: 50px;
display: flex;
margin-bottom: var(--size-2);
"
>
<div class="branch-card__icon">
<q-avatar size="md">
<q-img
:src="
props.row.imageUrl ?? '/no-profile.png'
"
>
<template #error>
<q-img src="/no-profile.png" />
</template>
</q-img>
</q-avatar>
<!-- <q-icon
size="md"
style="scale: 0.8"
:name="props.row.imageUrl"
/> -->
</div>
</div>
<div class="col">
<div class="col">
{{ props.row.customerName || '-' }}
</div>
<div class="col app-text-muted">
{{ props.row.customerNameEN || '-' }}
</div>
</div>
</div>
</q-td>
<q-td v-if="fieldSelected.includes('type')">
<span
class="tags"
:class="{
[`tags__${props.row.customerType === 'CORP' ? 'purple' : 'green'}`]: true,
}"
>
{{
props.row.customerType === 'CORP'
? $t('customerLegalEntity')
: $t('customerNaturalPerson')
}}
</span>
</q-td>
<q-td v-if="fieldSelected.includes('personName')">
{{ props.row.personName }}
</q-td>
<q-td v-if="fieldSelected.includes('telephoneNo')">
{{ props.row.branch[0]?.telephoneNo || '-' }}
</q-td>
<q-td v-if="fieldSelected.includes('branchEmail')">
{{ props.row.branch[0]?.email || '-' }}
</q-td>
<q-td>
<q-btn
icon="mdi-eye-outline"
:id="`btn-eye-${props.row.customerName}`"
size="sm"
dense
round
flat
@click.stop="
async () => {
await fetchListOfOptionBranch();
const { branch, ...payload } = props.row;
currentCustomer = payload;
currentCustomerId = props.row.id;
customerType = props.row.customerType;
assignFormData(props.row.id);
openDialogInputForm('INFO', props.row.id);
}
"
/>
<q-btn
icon="mdi-dots-vertical"
:id="`btn-dots-${props.row.code}`"
size="sm"
dense
round
flat
@click.stop
:key="props.row.id"
>
<q-menu class="bordered">
<q-list v-close-popup>
<q-item
:id="`view-detail-btn-${props.row.name}-view`"
@click.stop="
() => {
const { branch, ...payload } = props.row;
currentCustomer = payload;
currentCustomerId = props.row.id;
customerType = props.row.customerType;
assignFormData(props.row.id);
openDialogInputForm('INFO', props.row.id);
}
"
v-close-popup
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
>
<q-icon
name="mdi-eye-outline"
class="col-3"
size="xs"
style="color: hsl(var(--green-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('viewDetail') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-edit`"
v-close-popup
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
@click="
() => {
if (!listCustomer) return;
customerType = props.row.customerType;
const { branch, ...payload } = props.row;
currentCustomer = payload;
currentCustomerId = props.row.id;
assignFormData(props.row.id);
infoDrawerEdit = true;
openDialogInputForm('INFO', props.row.id);
}
"
>
<q-icon
name="mdi-pencil-outline"
class="col-3"
size="xs"
style="color: hsl(var(--cyan-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('edit') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-delete`"
dense
v-close-popup
:clickable="props.row.status === 'CREATED'"
class="row"
:class="{
'surface-3': props.row.status !== 'CREATED',
'app-text-muted':
props.row.status !== 'CREATED',
}"
style="white-space: nowrap"
@click="deleteCustomerById(props.row.id)"
>
<q-icon
name="mdi-trash-can-outline"
size="xs"
class="col-3"
:class="{
'app-text-negative':
props.row.status === 'CREATED',
}"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('delete') }}
</span>
</q-item>
<q-item dense>
<q-item-section class="q-py-sm">
<div class="q-pa-sm surface-2 rounded">
<q-toggle
:id="`view-detail-btn-${props.row.name}-status`"
dense
size="sm"
:label="
props.row.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
"
@click="
async () => {
triggerChangeStatus(
props.row.id,
props.row.status,
);
}
"
:model-value="
props.row.status !== 'INACTIVE'
"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-td>
</q-tr>
</template>
<template v-slot:item="props">
<div class="col-12 col-md-3 col-sm-6">
<PersonCard
:id="`card-${props.row.customerName}`"
:field-selected="fieldSelected"
separateEnter
history
:prefix-id="
props.row.customerNameEN ?? props.rowIndex
"
:data="{
code: props.row.code,
name:
$i18n.locale === 'en-US'
? `${props.row.customerName} `.trim()
: `${props.row.customerNameEN} `.trim(),
img: props.row.imageUrl,
male: undefined,
female: undefined,
detail: [
{
icon: 'mdi-cellphone',
value: props.row.branch[0]?.telephoneNo || '-',
},
{
icon: 'mdi-account',
value: props.row.personName || '-',
},
],
}"
:tag="[
{
color:
{
CORP: 'purple',
PERS: 'green',
}[props.row.customerType as string] || 'CORP',
value: $t(
props.row.customerType === 'CORP'
? 'customerLegalEntity'
: 'customerNaturalPerson',
),
},
]"
:disabled="props.row.status === 'INACTIVE'"
@history="openHistory(props.row.id)"
@update-card="
() => {
if (!listCustomer) return;
customerType = props.row.customerType;
const { branch, ...payload } = props.row;
currentCustomer = payload;
currentCustomerId = props.row.id;
assignFormData(props.row.id);
infoDrawerEdit = true;
openDialogInputForm('INFO', props.row.id);
}
"
@enter-card="
() => {
currentCustomerName = props.row.customerName;
customerType = props.row.customerType;
currentCustomerUrlImage = props.row.imageUrl;
currentCustomerId = props.row.id;
const { branch, ...payload } = props.row;
currentCustomer = payload;
statBranchNo =
branch[branch.length - 1].branchNo + 1;
isMainPage = false;
}
"
@view-card="
() => {
if (!listCustomer) return;
customerType = props.row.customerType;
const { branch, ...payload } = props.row;
currentCustomer = payload;
currentCustomerId = props.row.id;
assignFormData(props.row.id);
openDialogInputForm('INFO', props.row.id);
}
"
@delete-card="deleteCustomerById(props.row.id)"
@toggle-status="
triggerChangeStatus(props.row.id, props.row.status)
"
/>
</div>
</template>
</q-table>
</div>
<div
v-if="listCustomer.length !== 0"
class="row justify-between items-center q-px-md q-py-sm"
>
<div class="row col-4 items-center">
<div
class="app-text-muted"
style="width: 80px"
v-if="$q.screen.gt.sm"
>
{{ $t('showing') }}
</div>
<div>
<q-btn-dropdown
dense
unelevated
class="bordered q-pl-md rounded"
:label="pageSize"
style="background-color: var(--surface-1)"
>
<q-list>
<q-item
v-for="v in [10, 30, 50, 100, 500, 1000]"
:key="v"
clickable
v-close-popup
@click="
async () => {
pageSize = v;
await fetchListCustomer();
}
"
>
<q-item-section>
<q-item-label>{{ v }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</div>
<div class="col-4 flex justify-center app-text-muted">
{{
$t('recordsPage', {
resultcurrentPage: listCustomer.length,
total: statsCustomerType.PERS + statsCustomerType.CORP,
})
}}
</div>
<div class="col-4 flex justify-end">
<PaginationComponent
v-model:current-page="currentPageCustomer"
v-model:max-page="maxPageCustomer"
:fetch-data="
async () => {
await fetchListCustomer();
flowStore.rotate();
}
"
/>
</div>
</div>
</template>
<!-- employee -->
<template
v-if="
listEmployee &&
statsEmployee > 0 &&
selectorLabel === 'EMPLOYEE'
"
>
<div
v-if="listEmployee.length === 0"
class="row col full-width items-center justify-center"
style="min-height: 250px"
>
<NoData :not-found="!!inputSearch" />
</div>
<div
v-if="listEmployee.length !== 0"
class="surface-2 q-pa-md scroll col full-width"
>
<q-table
flat
bordered
:grid="modeView"
:rows="listEmployee"
:columns="columnsEmployee"
class="full-width"
card-container-class="q-col-gutter-md"
row-key="name"
:rows-per-page-options="[0]"
hide-pagination
:visible-columns="fieldSelected"
>
<template v-slot:header="props">
<q-tr
style="background-color: hsla(var(--info-bg) / 0.07)"
:props="props"
>
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<span v-if="col.label !== ''">
{{ $t(col.label) }}
</span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
'status-active': props.row.status !== 'INACTIVE',
'status-inactive': props.row.status === 'INACTIVE',
}"
:props="props"
:id="`row-table-${props.row.firstNameEN}`"
@click="
() => {
openDialogInputForm('INFO', props.row.id);
}
"
>
<q-td v-if="fieldSelected.includes('firstName')">
<div
class="row items-center"
style="flex-wrap: nowrap"
>
<div
style="
width: 50px;
display: flex;
margin-bottom: var(--size-2);
"
>
<div class="branch-card__icon">
<q-avatar size="md">
<q-img
:src="
props.row.profileImageUrl ??
'/no-profile.png'
"
>
<template #error>
<q-img src="/no-profile.png" />
</template>
</q-img>
</q-avatar>
</div>
</div>
<div class="col">
<div class="col">
{{
`${props.row.firstName} ${props.row.lastName}` ||
'-'
}}
<q-icon
class="q-pl-xs"
:class="{
'symbol-gender': props.row.gender,
'symbol-gender__male':
props.row.gender === 'male',
'symbol-gender__female':
props.row.gender === 'female',
}"
:name="`mdi-gender-${props.row.gender === 'male' ? 'male' : 'female'}`"
width="24px"
/>
</div>
<div class="col app-text-muted">
{{
`${props.row.firstNameEN} ${props.row.lastNameEN}` ||
'-'
}}
</div>
</div>
</div>
</q-td>
<q-td
v-if="
fieldSelected.includes('formDialogInputNationality')
"
>
{{ props.row.nationality || '-' }}
</q-td>
<q-td
v-if="
fieldSelected.includes('formDialogInputPassportNo')
"
>
{{ props.row.passportNumber || '-' }}
</q-td>
<q-td
v-if="fieldSelected.includes('formDialogInputAge')"
>
{{ calculateAge(props.row.dateOfBirth) }}
</q-td>
<q-td
v-if="fieldSelected.includes('passportExpiryDate')"
>
{{ dateFormat(props.row.passportExpiryDate) }}
</q-td>
<q-td
v-if="
fieldSelected.includes('formDialogEmployeeNRCNo')
"
>
{{ props.row.nrcNo || '-' }}
</q-td>
<q-td
v-if="fieldSelected.includes('formDialogInputAge')"
>
<div class="row items-center">
<div class="col">
<div class="col">
{{ props.row.customerBranch.code }}
</div>
<div class="col app-text-muted">
{{
$i18n.locale === 'en-US'
? `${props.row.customerBranch.nameEN}`
: `${props.row.customerBranch.name}`
}}
</div>
</div>
</div>
</q-td>
<q-td v-if="fieldSelected.includes('type')">
<span class="tags tags__pink">
{{ $t('EMPLOYEE') }}
</span>
</q-td>
<q-td>
<q-btn
icon="mdi-eye-outline"
size="sm"
dense
round
flat
@click.stop="
() => {
openDialogInputForm('INFO', props.row.id);
}
"
/>
<q-btn
icon="mdi-dots-vertical"
:id="`btn-dots-${props.row.code}`"
size="sm"
dense
round
flat
@click.stop
:key="props.row.id"
>
<q-menu class="bordered">
<q-list v-close-popup>
<q-item
:id="`view-detail-btn-${props.row.name}-view`"
@click.stop="
() => {
openDialogInputForm('INFO', props.row.id);
}
"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
>
<q-icon
name="mdi-eye-outline"
class="col-3"
size="xs"
style="color: hsl(var(--green-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('viewDetail') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-edit`"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
@click="
() => {
openDialogInputForm(
'INFO',
props.row.id,
true,
);
}
"
>
<q-icon
name="mdi-pencil-outline"
class="col-3"
size="xs"
style="color: hsl(var(--cyan-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('edit') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-delete`"
dense
:clickable="props.row.status === 'CREATED'"
class="row"
:class="{
'surface-3': props.row.status !== 'CREATED',
'app-text-muted':
props.row.status !== 'CREATED',
}"
style="white-space: nowrap"
@click="onDelete(props.row.id)"
>
<q-icon
name="mdi-trash-can-outline"
size="xs"
class="col-3"
:class="{
'app-text-negative':
props.row.status === 'CREATED',
}"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('delete') }}
</span>
</q-item>
<q-item dense>
<q-item-section class="q-py-sm">
<div class="q-pa-sm surface-2 rounded">
<q-toggle
:id="`view-detail-btn-${props.row.name}-status`"
dense
size="sm"
:label="
props.row.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
"
@click="
async () => {
triggerChangeStatus(
props.row.id,
props.row.status,
);
}
"
:model-value="
props.row.status !== 'INACTIVE'
"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-td>
</q-tr>
</template>
<template v-slot:item="props">
<div class="col-12 col-md-3 col-sm-6">
<PersonCard
:id="`card-${props.row.firstNameEN}`"
:field-selected="fieldSelected"
history
:prefix-id="props.row.firstNameEN ?? props.rowIndex"
:data="{
code: props.row.code,
name:
$i18n.locale === 'en-US'
? `${props.row.firstNameEN} ${props.row.lastNameEN} `.trim()
: `${props.row.firstName} ${props.row.lastName} `.trim(),
img: props.row.profileImageUrl,
male: props.row.gender === 'male',
female: props.row.gender === 'female',
detail: [
{
icon: 'mdi-passport',
value: props.row.nationality,
},
{
icon: 'mdi-clock-outline',
value: props.row.dateOfBirth
? calculateAge(props.row.dateOfBirth) ?? ''
: '',
},
],
}"
:tag="[
{
color: 'pink',
value: $t('EMPLOYEE'),
},
]"
:disabled="props.row.status === 'INACTIVE'"
@history="openHistory(props.row.id)"
@update-card="
(action) =>
openDialogInputForm(action, props.row.id, true)
"
@enter-card="
(action) =>
openDialogInputForm(action, props.row.id)
"
@delete-card="onDelete(props.row.id)"
@toggle-status="
triggerChangeStatus(props.row.id, props.row.status)
"
/>
</div>
</template>
</q-table>
</div>
<div
v-if="listEmployee.length !== 0"
class="row justify-between items-center q-px-md q-py-sm"
>
<div class="row col-4 items-center">
<div
class="app-text-muted"
style="width: 80px"
v-if="$q.screen.gt.sm"
>
{{ $t('showing') }}
</div>
<div>
<q-btn-dropdown
dense
unelevated
:label="pageSize"
class="bordered q-pl-md"
style="background-color: var(--surface-1)"
>
<q-list>
<q-item
v-for="v in [10, 30, 50, 100, 500, 1000]"
:key="v"
clickable
v-close-popup
@click="
async () => {
pageSize = v;
await fetchListEmployee();
}
"
>
<q-item-section>
<q-item-label>{{ v }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</div>
<div class="col-4 flex justify-center app-text-muted">
{{
$t('recordsPage', {
resultcurrentPage: listEmployee.length,
total: statsEmployee,
})
}}
</div>
<div class="col-4 flex justify-end">
<PaginationComponent
v-model:current-page="currentPageEmployee"
v-model:max-page="maxPageEmployee"
:fetch-data="
async () => {
await fetchListEmployee();
flowStore.rotate();
}
"
/>
</div>
</div>
</template>
<template
v-if="
(statsCustomerType.CORP + statsCustomerType.PERS === 0 &&
selectorLabel === 'EMPLOYER') ||
(statsEmployee === 0 && selectorLabel === 'EMPLOYEE')
"
>
<TooltipComponent
class="self-end q-ma-md"
:title="
selectorLabel === 'EMPLOYER'
? 'customerEmployerTooltipTitle'
: 'customerEmployeeTooltipTitle'
"
:caption="
selectorLabel === 'EMPLOYER'
? 'customerEmployerTooltipCaption'
: 'customerEmployeeTooltipCaption'
"
imgSrc="personnel-table-"
/>
<div
class="row items-center justify-center"
style="flex-grow: 1"
>
<AddButton
:label="
selectorLabel === 'EMPLOYER'
? 'customerEmployerAdd'
: 'customerEmployeeAdd'
"
@trigger="() => openDialogCustomerType()"
/>
</div>
</template>
</div>
</template>
</q-splitter>
</div>
</div>
<div class="col column surface-1" v-else>
<CustomerInfoComponent
:customer-type="customerType"
:customer-id="currentCustomerId"
v-model:mode-view="modeView"
@back="
() => {
isMainPage = true;
statBranchNo = 1;
indexTab = 0;
currentCustomerUrlImage = null;
clearForm();
}
"
@viewDetail="
async (v, i) => {
await fetchListOfOptionBranch();
currentBranchId = v.id;
statusToggle = v.status === 'INACTIVE' ? false : true;
currentBranch = {
name: v.name,
code: v.code,
};
if (currentCustomer) assignFormData(currentCustomer.id, v, i);
infoDrawerBranch = true;
}
"
v-model:branch="branch"
v-model:currentCustomerName="currentCustomerName"
v-model:currentCustomerUrlImage="currentCustomerUrlImage"
/>
</div>
</div>
<FormDialog
v-model:modal="dialogCustomerType"
:title="$t('customerCardUserType')"
no-footer
no-app-box
width="60vw"
height="50vh"
:close="
() => {
clearForm();
dialogCustomerType = false;
}
"
>
<div class="row full-width items-center">
<ItemCard
class="col q-mx-sm"
v-for="i in itemCard"
:key="i.text"
:icon="i.icon"
:text="i.text"
:color="i.color"
@trigger="
() => {
triggerCreate(i.text === 'customerLegalEntity' ? 'CORP' : 'PERS');
}
"
/>
</div>
</FormDialog>
<FormDialog
v-model:modal="dialogInputForm"
:title="$t('customerEmployerAdd')"
:customer-label="customerType"
:hiddenBtnSave="false"
:submit="() => {}"
:close="
() => {
if (hideBranch && countStartsOne === 1) {
dialog({
color: 'warning',
icon: 'mdi-alert',
title: t('warning'),
actionText: t('ok'),
persistent: true,
message: t('notRecorded'),
action: async () => {
countStartsOne++;
clearForm();
dialogInputForm = false;
},
cancel: () => {},
});
} else {
clearForm();
dialogInputForm = false;
}
}
"
>
<template #prepend>
<ProfileUpload
prefix-id="form-dialog"
v-model:url-profile="profileUrl"
v-model:status-toggle="statusToggle"
v-model:profile-submit="profileSubmit"
@input-file="inputFile.click()"
@cancel-file="inputFile.value = ''"
/>
</template>
<template #information>
<BasicInformation
dense
outlined
separator
prefix-id="form-dialog"
:type-customer="customerType"
v-model:options-branch="branchOption"
v-model:registered-branch-id="formData.registeredBranchId"
v-model:customer-name="formData.customerName"
v-model:customer-name-en="formData.customerNameEN"
v-model:person-name="formData.personName"
v-model:tax-no="formData.taxNo"
:show-btn-save="true"
@save="
async () => {
await onSubmitBasicInformation();
console.log('สร้าง');
}
"
/>
</template>
<template #address>
<!-- <FormCustomerBranch separator dense outlined /> -->
<div v-if="!hideBranch">
<div class="col-3 app-text-muted">
• {{ $t('formDialogCustomerBranch') }}
</div>
<div class="col-12 row bordered q-pt-none rounded">
<TabComponent
prefix-id="form-dialog"
v-model:branch-no="statBranchNo"
v-model:stat-branch-no="statBranchNo"
v-model:customer-branch="formData.customerBranch"
v-model:tab-index="indexTab"
@save="() => onSubmitCustomerBranch({ isClearForm: false })"
>
<template #address>
<FormAddress
prefix-id="form-dialog"
:indexId="indexTab"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
v-model:address="formData.customerBranch[indexTab].address"
v-model:address-e-n="
formData.customerBranch[indexTab].addressEN
"
v-model:province-id="
formData.customerBranch[indexTab].provinceId
"
v-model:district-id="
formData.customerBranch[indexTab].districtId
"
v-model:sub-district-id="
formData.customerBranch[indexTab].subDistrictId
"
v-model:zip-code="formData.customerBranch[indexTab].zipCode"
:title="$t('formDialogTitleEmployerAddress')"
separator
dense
outlined
/>
</template>
<template #businessInformation>
<FormBusiness
prefix-id="form-dialog"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
v-model:employment-office="
formData.customerBranch[indexTab].employmentOffice
"
v-model:bussiness-type="
formData.customerBranch[indexTab].bussinessType
"
v-model:bussiness-type-en="
formData.customerBranch[indexTab].bussinessTypeEN
"
v-model:job-position="
formData.customerBranch[indexTab].jobPosition
"
v-model:job-position-en="
formData.customerBranch[indexTab].jobPositionEN
"
v-model:job-description="
formData.customerBranch[indexTab].jobDescription
"
v-model:sale-employee="
formData.customerBranch[indexTab].saleEmployee
"
v-model:pay-date="formData.customerBranch[indexTab].payDate"
v-model:wage-rate="formData.customerBranch[indexTab].wageRate"
separator
dense
outlined
/>
</template>
<template #about>
<AboutComponent
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
prefix-id="form-dialog"
:type-customer="customerType"
v-model:branch-no="formData.customerBranch[indexTab].branchNo"
v-model:tax-no="formData.customerBranch[indexTab].taxNo"
v-model:customer-name="formData.customerBranch[indexTab].name"
v-model:customer-english-name="
formData.customerBranch[indexTab].nameEN
"
v-model:authorized-capital="
formData.customerBranch[indexTab].authorizedCapital
"
v-model:register-name="
formData.customerBranch[indexTab].registerName
"
v-model:register-date="
formData.customerBranch[indexTab].registerDate
"
dense
outlined
separator
/>
</template>
<template #contactInformation>
<ContactComponent
prefix-id="form-dialog"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
v-model:mail="formData.customerBranch[indexTab].email"
v-model:telephone="
formData.customerBranch[indexTab].telephoneNo
"
dense
outlined
separator
/>
</template>
<template #otherDocuments>
<OtherInformation
prefix-id="form-dialog"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
dense
outlined
/>
</template>
</TabComponent>
</div>
</div>
</template>
</FormDialog>
<!-- Employee Form -->
<FormDialog
employee
disabledRule
:hiddenBtnSave="false"
addressSeparator
v-model:modal="dialogEmployee"
:noAddress="formDataEmployeeTab !== 'personalInfo'"
:noPaddingTab="
formDataEmployeeTab === 'healthCheck' ||
formDataEmployeeTab === 'workHistory'
"
:tabs-list="
employeeTab.filter((x) => {
if (hideTab) {
return x.name === 'personalInfo';
}
return true;
})
"
v-model:current-tab="formDataEmployeeTab"
v-model:same-with-employer="formDataEmployeeSameAddr"
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"
:title="$t('customerEmployeeAdd')"
:submit="
() => {
// isEmployeeEdit
// ? currentEmployee && onSubmitEdit(currentEmployee.id)
// : onSubmit();
}
"
:close="
() => {
clearFormEmployee();
}
"
>
<template #prepend>
<ProfileUpload
prefix-id="form-dialog"
v-model:url-profile="profileUrl"
v-model:status-toggle="statusToggle"
v-model:profile-submit="profileSubmit"
@input-file="inputFile.click()"
@cancel-file="inputFile.value = ''"
/>
</template>
<template #information>
<BasicInformation
prefix-id="form-dialog"
v-if="formDataEmployeeTab === 'personalInfo'"
employee
dense
outlined
separator
:employee-owner-option="employeeStore.ownerOption"
v-model:customer-branch="formDataEmployeeOwner"
v-model:employee-id="currentEmployeeCode"
v-model:nrc-no="formDataEmployee.nrcNo"
v-model:person-name="formData.personName"
@filter-owner-branch="employeeFilterOwnerBranch"
/>
</template>
<template #person>
<FormPerson
prefix-id="form-dialog"
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
employee
separator
:title="$t('personalInfo')"
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
prefix-id="form-dialog"
v-if="
formDataEmployeeTab === 'healthCheck' &&
formDataEmployee.employeeCheckup
"
show-btn-save
dense
outlined
v-model:employee-checkup="formDataEmployee.employeeCheckup"
v-model:checkup-type-option="optionStore.globalOption.nationality"
v-model:medical-benefit-option="optionStore.globalOption.typeInsurance"
v-model:insurance-company-option="
optionStore.globalOption.insurancePlace
"
@save="
(index) => {
onSubmitEmployee('healthCheck', index);
}
"
@remove="
(index) => {
deleteByIdCheckOrwork(
formDataEmployee.employeeCheckup?.[index].id || '',
'healthCheck',
index,
);
}
"
/>
<FormEmployeeWorkHistory
prefix-id="form-dialog"
v-if="formDataEmployeeTab === 'workHistory'"
dense
outlined
v-model:employee-work="formDataEmployee.employeeWork"
v-model:position-name-option="optionStore.globalOption.position"
v-model:job-type-option="optionStore.globalOption.businessType"
v-model:workplace-option="optionStore.globalOption.area"
show-btn-save
@save="
(index) => {
onSubmitEmployee('workHistory', index);
}
"
@remove="
(index) => {
deleteByIdCheckOrwork(
formDataEmployee.employeeWork?.[index].id || '',
'healthCheck',
index,
);
}
"
/>
<FormEmployeeOther
prefix-id="form-dialog"
v-if="
formDataEmployeeTab === 'other' && formDataEmployee.employeeOtherInfo
"
dense
outlined
v-model:employee-other="formDataEmployee.employeeOtherInfo"
show-btn-save
@save="() => onSubmitEmployee('other')"
/>
</template>
<template #by-type>
<FormEmployeePassport
prefix-id="form-dialog"
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
separator
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="optionStore.globalOption.nationality"
v-model:passport-issuing-country-option="
optionStore.globalOption.nationality
"
/>
<FormEmployeeVisa
prefix-id="form-dialog"
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
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="optionStore.globalOption.nationality"
show-btn-save
@save="
() => {
onSubmitEmployee('personalInfo');
}
"
/>
</template>
</FormDialog>
<FormDialog
v-model:modal="dialogInputCustomerBranchForm"
:title="$t('formDialogTitleCreateSubBranch')"
:submit="() => {}"
:close="
() => {
clearForm();
dialogInputCustomerBranchForm = false;
}
"
>
<template #address>
<!-- <FormCustomerBranch separator dense outlined /> -->
<div class="col-3 app-text-muted">
• {{ $t('formDialogCustomerBranch') }}
</div>
<div class="col-12 row bordered q-pt-none rounded">
<TabComponent
prefix-id="form-dialog"
:stat-branch-no="statBranchNo"
v-model:customer-branch="formData.customerBranch"
v-model:tab-index="indexTab"
@save="
() => {
onSubmitCustomerBranch({ isClearForm: true });
}
"
>
<template #address>
<FormAddress
prefix-id="form-dialog"
:indexId="indexTab"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
v-model:address="formData.customerBranch[indexTab].address"
v-model:address-e-n="formData.customerBranch[indexTab].addressEN"
v-model:province-id="formData.customerBranch[indexTab].provinceId"
v-model:district-id="formData.customerBranch[indexTab].districtId"
v-model:sub-district-id="
formData.customerBranch[indexTab].subDistrictId
"
v-model:zip-code="formData.customerBranch[indexTab].zipCode"
separator
dense
outlined
/>
</template>
<template #businessInformation>
<FormBusiness
prefix-id="form-dialog"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
v-model:employment-office="
formData.customerBranch[indexTab].employmentOffice
"
v-model:bussiness-type="
formData.customerBranch[indexTab].bussinessType
"
v-model:bussiness-type-en="
formData.customerBranch[indexTab].bussinessTypeEN
"
v-model:job-position="
formData.customerBranch[indexTab].jobPosition
"
v-model:job-position-en="
formData.customerBranch[indexTab].jobPositionEN
"
v-model:job-description="
formData.customerBranch[indexTab].jobDescription
"
v-model:sale-employee="
formData.customerBranch[indexTab].saleEmployee
"
v-model:pay-date="formData.customerBranch[indexTab].payDate"
v-model:wage-rate="formData.customerBranch[indexTab].wageRate"
separator
dense
outlined
/>
</template>
<template #about>
<AboutComponent
prefix-id="form-dialog"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
:type-customer="customerType"
v-model:branch-no="formData.customerBranch[indexTab].branchNo"
v-model:tax-no="formData.customerBranch[indexTab].taxNo"
v-model:customer-name="formData.customerBranch[indexTab].name"
v-model:customer-english-name="
formData.customerBranch[indexTab].nameEN
"
v-model:authorized-capital="
formData.customerBranch[indexTab].authorizedCapital
"
v-model:register-name="
formData.customerBranch[indexTab].registerName
"
v-model:register-date="
formData.customerBranch[indexTab].registerDate
"
dense
outlined
separator
/>
</template>
<template #contactInformation>
<ContactComponent
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
prefix-id="form-dialog"
v-model:mail="formData.customerBranch[indexTab].email"
v-model:telephone="formData.customerBranch[indexTab].telephoneNo"
dense
outlined
separator
/>
</template>
<template #otherDocuments>
<OtherInformation
prefix-id="form-dialog"
v-if="
indexTab !== undefined && formData.customerBranch?.[indexTab]
"
dense
outlined
/>
</template>
</TabComponent>
</div>
</template>
</FormDialog>
<!-- DRAWER INFO ของ นายจ้าง -->
<DrawerInfo
:title="
$t(
currentCustomer?.customerType === 'CORP'
? 'formTitleCustomer'
: 'formTitleCustomerNaturalPerson',
{ msg: currentCustomer?.customerName },
)
"
v-model:drawer-open="infoDrawer"
:badgeLabel="currentCustomer?.code"
:badgeClass="
currentCustomer?.customerType === 'CORP' ? 'app-bg-corp' : 'app-bg-pers'
"
:undo="() => undo()"
:isEdit="infoDrawerEdit"
:close="() => onClose()"
:editData="() => (infoDrawerEdit = true)"
:submit="() => onSubmitEdit(currentCustomerId)"
:deleteData="() => deleteCustomerById(currentCustomerId)"
>
<template #info>
<InfoForm>
<template #person-card>
<UsersDetailCardComponent
:can-edit-profile="infoDrawerEdit"
:hideButton="true"
v-if="!!currentCustomer"
no-bg
no-detail
no-hover
:color="
currentCustomer.customerType === 'CORP' ? 'purple' : 'green'
"
:metadata="{
id: '1',
disabled: currentCustomer.status === 'ACTIVE',
}"
:list="{
id: '1',
type: currentCustomer.customerType,
name: currentCustomer.customerName,
imageUrl: currentCustomer.imageUrl,
status: currentCustomer.status,
code: 'HQ006',
}"
@edit-profile="
() => {
inputFile.click();
}
"
/>
</template>
<template #information>
<BasicInformation
prefix-id="drawer-info-customer"
dense
outlined
separator
:show-btn-save="true"
:readonly="!infoDrawerEdit"
:type-customer="customerType"
v-model:options-branch="branchOption"
v-model:registered-branch-id="formData.registeredBranchId"
v-model:customer-name="formData.customerName"
v-model:customer-name-en="formData.customerNameEN"
v-model:person-name="formData.personName"
v-model:tax-no="formData.taxNo"
@save="
() => {
console.log('แก้ไข');
}
"
/>
</template>
<template #address>
<div class="col-3 app-text-muted">
• {{ $t('formDialogCustomerBranch') }}
</div>
<div class="col-12 row bordered q-pt-none rounded">
<TabComponent
prefix-id="drawer-info-customer"
:stat-branch-no="statBranchNo"
:readonly="!infoDrawerEdit"
v-model:customer-branch="formData.customerBranch"
v-model:tab-index="indexTab"
@save="() => onSubmitCustomerBranch({ isClearForm: false })"
>
<template #address>
<FormAddress
prefix-id="drawer-info-customer"
:indexId="indexTab"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
v-model:address="formData.customerBranch[indexTab].address"
v-model:address-e-n="
formData.customerBranch[indexTab].addressEN
"
v-model:province-id="
formData.customerBranch[indexTab].provinceId
"
v-model:district-id="
formData.customerBranch[indexTab].districtId
"
v-model:sub-district-id="
formData.customerBranch[indexTab].subDistrictId
"
v-model:zip-code="formData.customerBranch[indexTab].zipCode"
separator
dense
outlined
:readonly="!infoDrawerEdit"
/>
</template>
<template #businessInformation>
<FormBusiness
prefix-id="drawer-info-customer"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
v-model:employment-office="
formData.customerBranch[indexTab].employmentOffice
"
v-model:bussiness-type="
formData.customerBranch[indexTab].bussinessType
"
v-model:bussiness-type-en="
formData.customerBranch[indexTab].bussinessTypeEN
"
v-model:job-position="
formData.customerBranch[indexTab].jobPosition
"
v-model:job-position-en="
formData.customerBranch[indexTab].jobPositionEN
"
v-model:job-description="
formData.customerBranch[indexTab].jobDescription
"
v-model:sale-employee="
formData.customerBranch[indexTab].saleEmployee
"
v-model:pay-date="formData.customerBranch[indexTab].payDate"
v-model:wage-rate="formData.customerBranch[indexTab].wageRate"
separator
dense
outlined
:readonly="!infoDrawerEdit"
/>
</template>
<template #about>
<AboutComponent
prefix-id="drawer-info-customer"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
:type-customer="customerType"
v-model:legal-entity-code="
formData.customerBranch[indexTab].legalPersonNo
"
v-model:tax-no="formData.customerBranch[indexTab].taxNo"
v-model:branch-code="formData.customerBranch[indexTab].code"
v-model:branch-no="formData.customerBranch[indexTab].branchNo"
v-model:customer-name="formData.customerBranch[indexTab].name"
v-model:customer-english-name="
formData.customerBranch[indexTab].nameEN
"
v-model:authorized-capital="
formData.customerBranch[indexTab].authorizedCapital
"
v-model:register-name="
formData.customerBranch[indexTab].registerName
"
v-model:register-date="
formData.customerBranch[indexTab].registerDate
"
dense
outlined
separator
:readonly="!infoDrawerEdit"
/>
</template>
<template #contactInformation>
<ContactComponent
prefix-id="drawer-info-customer"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
v-model:mail="formData.customerBranch[indexTab].email"
v-model:telephone="
formData.customerBranch[indexTab].telephoneNo
"
dense
outlined
separator
:readonly="!infoDrawerEdit"
/>
</template>
<template #otherDocuments>
<OtherInformation
prefix-id="drawer-info-customer"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
dense
outlined
:readonly="!infoDrawerEdit"
/>
</template>
</TabComponent>
</div>
</template>
</InfoForm>
</template>
</DrawerInfo>
<!-- DRAWER INFO ของ สาขา -->
<DrawerInfo
:title="$t('formTitleBranch', { msg: currentBranch.name })"
v-model:drawer-open="infoDrawerBranch"
:badgeLabel="currentBranch.code"
:badgeClass="
currentCustomer?.customerType === 'CORP' ? 'app-bg-corp' : 'app-bg-pers'
"
:undo="
() => {
cloneData();
infoDrawerEdit = false;
}
"
:isEdit="infoDrawerEdit"
:close="() => onCloseBranch()"
:editData="() => (infoDrawerEdit = true)"
:deleteData="() => deleteBranchId(currentBranchId)"
:submit="
() => {
console.log(formData.customerBranch?.[indexTab]);
submitBranch();
}
"
>
<template #info>
<InfoForm>
<template #person-card>
<UsersDetailCardComponent
:hideButton="true"
v-if="!!currentCustomer"
no-bg
no-detail
no-hover
:color="
currentCustomer.customerType === 'CORP' ? 'purple' : 'green'
"
:metadata="{
id: '1',
disabled: currentCustomer.status === 'ACTIVE',
}"
:list="{
id: '1',
type: currentCustomer.customerType,
name: currentCustomer.customerName,
imageUrl: currentCustomer.imageUrl,
status: currentCustomer.status,
code: 'HQ006',
}"
/>
<div class="text-left q-pt-md" v-if="infoDrawerEdit">
<q-toggle
id="toggle-status"
dense
size="md"
v-model="statusToggle"
padding="none"
class="q-pr-md"
/>
<span>สถานะสาขา</span>
</div>
</template>
<template #information>
<BasicInformation
prefix-id="drawer-info-customer-branch"
dense
outlined
separator
:readonly="true"
:type-customer="customerType"
v-model:options-branch="branchOption"
v-model:registered-branch-id="formData.registeredBranchId"
v-model:customer-name="formData.customerName"
v-model:customer-name-en="formData.customerNameEN"
v-model:person-name="formData.personName"
v-model:tax-no="formData.taxNo"
/>
</template>
<template #address>
<div class="col-3 app-text-muted">
• {{ $t('formDialogCustomerBranch') }}
</div>
<div class="col-12 row bordered q-pt-none rounded">
<TabComponent
:stat-branch-no="statBranchNo"
prefix-id="drawer-info-customer-branch"
:edit="infoDrawerEdit"
:readonly="!infoDrawerEdit"
v-model:customer-branch="formData.customerBranch"
v-model:tab-index="indexTab"
>
<template #address>
<FormAddress
prefix-id="drawer-info-customer-branch"
:indexId="indexTab"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
v-model:address="formData.customerBranch[indexTab].address"
v-model:address-e-n="
formData.customerBranch[indexTab].addressEN
"
v-model:province-id="
formData.customerBranch[indexTab].provinceId
"
v-model:district-id="
formData.customerBranch[indexTab].districtId
"
v-model:sub-district-id="
formData.customerBranch[indexTab].subDistrictId
"
v-model:zip-code="formData.customerBranch[indexTab].zipCode"
separator
dense
outlined
:readonly="!infoDrawerEdit"
/>
</template>
<template #businessInformation>
<FormBusiness
prefix-id="drawer-info-customer-branch"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
v-model:employment-office="
formData.customerBranch[indexTab].employmentOffice
"
v-model:bussiness-type="
formData.customerBranch[indexTab].bussinessType
"
v-model:bussiness-type-en="
formData.customerBranch[indexTab].bussinessTypeEN
"
v-model:job-position="
formData.customerBranch[indexTab].jobPosition
"
v-model:job-position-en="
formData.customerBranch[indexTab].jobPositionEN
"
v-model:job-description="
formData.customerBranch[indexTab].jobDescription
"
v-model:sale-employee="
formData.customerBranch[indexTab].saleEmployee
"
v-model:pay-date="formData.customerBranch[indexTab].payDate"
v-model:wage-rate="formData.customerBranch[indexTab].wageRate"
separator
dense
outlined
:readonly="!infoDrawerEdit"
/>
</template>
<template #about>
<AboutComponent
prefix-id="drawer-info-customer-branch"
v-if="formData.customerBranch?.[0]"
:type-customer="customerType"
v-model:branch-code="formData.customerBranch[indexTab].code"
v-model:branch-no="formData.customerBranch[indexTab].branchNo"
v-model:customer-name="formData.customerBranch[indexTab].name"
v-model:customer-english-name="
formData.customerBranch[indexTab].nameEN
"
v-model:authorized-capital="
formData.customerBranch[indexTab].authorizedCapital
"
v-model:register-name="
formData.customerBranch[indexTab].registerName
"
v-model:register-date="
formData.customerBranch[indexTab].registerDate
"
dense
outlined
separator
:readonly="!infoDrawerEdit"
/>
</template>
<template #contactInformation>
<ContactComponent
prefix-id="drawer-info-customer-branch"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
v-model:mail="formData.customerBranch[indexTab].email"
v-model:telephone="
formData.customerBranch[indexTab].telephoneNo
"
dense
outlined
separator
:readonly="!infoDrawerEdit"
/>
</template>
<template #otherDocuments>
<OtherInformation
prefix-id="drawer-info-customer-branch"
v-if="
indexTab !== undefined &&
formData.customerBranch?.[indexTab]
"
dense
outlined
:readonly="!infoDrawerEdit"
/>
</template>
</TabComponent>
</div>
</template>
</InfoForm>
</template>
</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="undo"
:close="clearFormEmployee"
:deleteData="
() => {
currentEmployee && onDelete(currentEmployee.id);
}
"
:submit="
() => {
currentEmployee && onSubmitEdit(currentEmployee.id);
}
"
bg-color="surface-tab"
>
<InfoForm
v-if="optionStore.globalOption"
:readonly="!infoDrawerEmployeeEdit"
:noAddress="formDataEmployeeTab !== 'personalInfo'"
:noPaddingTab="
formDataEmployeeTab === 'healthCheck' ||
formDataEmployeeTab === 'workHistory'
"
v-model:same-with-employer="formDataEmployeeSameAddr"
: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"
disabledRule
employee
>
<template #person-card>
<PersonCard
:can-edit-profile="infoDrawerEmployeeEdit"
prefix-id="drawer-edit"
no-hover
no-action
no-detail
:data="{
name: formDataEmployee.firstName + ' ' + formDataEmployee.lastName,
code: formDataEmployee.code,
male: formDataEmployee.gender === 'male',
female: formDataEmployee.gender === 'female',
img: profileUrl || undefined,
}"
:list="infoEmployeePersonCard ? infoEmployeePersonCard : []"
:gridColumns="1"
@edit-profile="
() => {
inputFile.click();
}
"
/>
</template>
<template #information>
<BasicInformation
prefix-id="drawer-info-employee"
v-if="formDataEmployeeTab === 'personalInfo'"
employee
dense
outlined
separator
:readonly="!infoDrawerEmployeeEdit"
:employee-owner-option="employeeStore.ownerOption"
v-model:customer-branch="formDataEmployeeOwner"
v-model:employee-id="currentEmployeeCode"
v-model:nrc-no="formDataEmployee.nrcNo"
v-model:person-name="formData.personName"
@filter-owner-branch="employeeFilterOwnerBranch"
/>
</template>
<template #person>
<FormPerson
prefix-id="drawer-info-employee"
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
employee
separator
:title="$t('personalInfo')"
: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
prefix-id="drawer-info-employee"
v-if="
formDataEmployeeTab === 'healthCheck' &&
formDataEmployee.employeeCheckup
"
:readonly="!infoDrawerEmployeeEdit"
dense
outlined
v-model:employee-checkup="formDataEmployee.employeeCheckup"
v-model:checkup-type-option="optionStore.globalOption.nationality"
v-model:medical-benefit-option="
optionStore.globalOption.typeInsurance
"
v-model:insurance-company-option="
optionStore.globalOption.insurancePlace
"
/>
<FormEmployeeWorkHistory
prefix-id="drawer-info-employee"
v-if="formDataEmployeeTab === 'workHistory'"
dense
outlined
:readonly="!infoDrawerEmployeeEdit"
v-model:employee-work="formDataEmployee.employeeWork"
v-model:position-name-option="optionStore.globalOption.position"
v-model:job-type-option="optionStore.globalOption.businessType"
v-model:workplace-option="optionStore.globalOption.area"
/>
<FormEmployeeOther
prefix-id="drawer-info-employee"
v-if="
formDataEmployeeTab === 'other' &&
formDataEmployee.employeeOtherInfo
"
:readonly="!infoDrawerEmployeeEdit"
dense
outlined
v-model:employee-other="formDataEmployee.employeeOtherInfo"
/>
</template>
<template #by-type>
<FormEmployeePassport
prefix-id="drawer-info-employee"
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
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="optionStore.globalOption.nationality"
v-model:passport-issuing-country-option="
optionStore.globalOption.nationality
"
/>
<FormEmployeeVisa
prefix-id="drawer-info-employee"
v-if="formDataEmployeeTab === 'personalInfo'"
dense
outlined
: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="optionStore.globalOption.nationality"
/>
</template>
</InfoForm>
</DrawerInfo>
<!-- employee history -->
<FormDialog
no-address
no-app-box
no-footer
:title="$t('editHistory')"
v-model:modal="employeeHistoryDialog"
:close="() => (employeeHistoryDialog = false)"
v-if="employeeHistory"
>
<HistoryEditComponent v-model:history-list="employeeHistory" />
</FormDialog>
</template>
<style scoped>
.customer-row {
display: grid;
gap: var(--size-6);
transition: 0.3s ease-in-out;
}
.hover-card:hover {
cursor: pointer;
border-radius: 10px;
box-shadow: var(--shadow-3);
}
.slide-enter-active {
transition: all 0.1s ease-out;
}
.slide-leave-active {
transition: all 0.1s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-enter-from,
.slide-leave-to {
transform: translateY(-20px);
opacity: 0;
}
.employer-active {
background-color: hsla(var(--info-bg) / 0.1);
color: hsl(var(--info-bg));
}
.tags {
display: inline-block;
color: hsla(var(--_color) / 1);
background: hsla(var(--_color) / 0.15);
border-radius: var(--radius-2);
padding-inline: var(--size-2);
}
.tags__pink {
--_color: var(--pink-6-hsl);
}
.tags__purple {
--_color: var(--violet-11-hsl);
}
.tags__green {
--_color: var(--teal-10-hsl);
}
.dark .tags__purple {
--_color: var(--violet-10-hsl);
}
.dark .tags__green {
--_color: var(--teal-8-hsl);
}
.status-active {
--_branch-status-color: var(--green-6-hsl);
}
.status-inactive {
--_branch-status-color: var(--red-4-hsl);
--_branch-badge-bg: var(--red-4-hsl);
filter: grayscale(0.5);
opacity: 0.5;
}
.branch-card__icon {
background-color: hsla(var(--_branch-card-bg) / 0.15);
border-radius: 50%;
padding: var(--size-1);
position: relative;
transform: rotate(45deg);
&::after {
content: ' ';
display: block;
block-size: 0.5rem;
aspect-ratio: 1;
position: absolute;
border-radius: 50%;
right: -0.1rem;
top: calc(50% - 0.25rem);
bottom: calc(50% - 0.25rem);
background-color: hsla(var(--_branch-status-color) / 1);
}
& :deep(.q-avatar) {
transform: rotate(-45deg);
color: hsla(var(--_branch-card-bg) / 1);
}
}
& .symbol-gender {
color: hsla(var(--_fg));
&.symbol-gender__male {
--_fg: var(--gender-male);
}
&.symbol-gender__female {
--_fg: var(--gender-female);
}
}
</style>