fix: customer

This commit is contained in:
puriphatt 2024-09-16 14:38:04 +07:00
parent cfaf1467a6
commit 4bf1a4a346
11 changed files with 1569 additions and 533 deletions

View file

@ -23,6 +23,7 @@ defineProps<{
prefixId: string;
hideTitle?: boolean;
useEmployment?: boolean;
useWorkPlace?: boolean;
}>();
@ -43,6 +44,14 @@ const subDistrictId = defineModel<string | null | undefined>('subDistrictId');
const zipCode = defineModel<string | null | undefined>('zipCode');
const sameWithEmployer = defineModel<boolean>('sameWithEmployer');
const homeCode = defineModel<string | null | undefined>('homeCode');
const employmentOffice = defineModel<string | null | undefined>(
'employmentOffice',
);
const employmentOfficeEN = defineModel<string | null | undefined>(
'employmentOfficeEN',
);
const addrOptions = reactive<{
provinceOps: Province[];
districtOps: District[];
@ -274,6 +283,43 @@ watch(districtId, fetchSubDistrict);
</div>
<div class="col-12 row q-col-gutter-y-md">
<div v-if="useEmployment" class="col-12 row q-col-gutter-sm">
<q-input
outlined
hide-bottom-space
class="col-3"
v-model="homeCode"
:dense="dense"
:label="$t('customer.form.homeCode')"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-input
outlined
hide-bottom-space
class="col"
v-model="employmentOffice"
:dense="dense"
:label="$t('customer.form.employmentOffice')"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
/>
<q-input
outlined
hide-bottom-space
class="col"
v-model="employmentOfficeEN"
:dense="dense"
:label="`${$t('customer.form.employmentOffice')} (EN)`"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-address-${indexId}` : 'input-address'}`"
/>
</div>
<div class="col-12 app-text-muted-2">
<q-icon size="xs" class="q-mr-xs" name="mdi-map-marker-outline" />
{{ addressTitle || $t('form.address') }}

View file

@ -563,7 +563,7 @@ function customerFormUndo(close = true) {
customerFormState.value.readonly = true;
}
function createCustomerForm(customerType: 'CORP' | 'PERS') {
async function createCustomerForm(customerType: 'CORP' | 'PERS') {
customerFormState.value.dialogModal = true;
customerFormState.value.dialogType = 'create';
customerFormData.value.customerType = customerType;
@ -1765,6 +1765,7 @@ const emptyCreateDialog = ref(false);
customerFormStore.resetForm(customerFormState.dialogType === 'create');
onCreateImageList = { selectedImage: '', list: [] };
await fetchListOfOptionBranch();
await customerFormStore.addCurrentCustomerBranch();
}
"
:on-close="
@ -1777,23 +1778,22 @@ const emptyCreateDialog = ref(false);
<template #header>
<DialogHeader
:title="
$t(`form.title.${customerFormState.dialogType}`, {
name: `${$t('customer.employer')} ${
customerFormData.customerType === 'CORP'
? $t('customer.employerLegalEntity')
: $t('customer.employerNaturalPerson')
}`,
$t(`general.add`, {
text: `${$t('customer.employer')} `,
})
"
>
<template
v-if="
customerFormState.dialogType !== 'create' &&
customerFormState.editCustomerCode
"
#title-after
>
{{ customerFormState.editCustomerCode }}
<template #title-after>
<span
:style="`color: hsla(var(--${customerFormData.customerType === 'PERS' ? 'teal-10-hsl' : 'violet-11-hsl'})/1)`"
>
:
{{
customerFormData.customerType === 'CORP'
? $t('customer.employerLegalEntity')
: $t('customer.employerNaturalPerson')
}}
</span>
</template>
</DialogHeader>
</template>
@ -1876,17 +1876,16 @@ const emptyCreateDialog = ref(false);
<q-form
@submit.prevent="
async () => {
await customerFormStore.submitFormCustomer(onCreateImageList);
customerFormState.readonly = true;
console.log(customerFormData);
// await customerFormStore.submitFormCustomer(onCreateImageList);
// customerFormState.readonly = true;
notify('create', $t('general.success'));
await fetchListCustomer();
// await fetchListCustomer();
}
"
greedy
:style="{
opacity: customerFormState.branchIndex !== -1 ? '0.5' : undefined,
}"
>
<!-- :create="customerFormState.dialogType === 'create'" -->
<EmployerFormBasicInfo
class="q-mb-xl"
:readonly="
@ -1896,7 +1895,7 @@ const emptyCreateDialog = ref(false);
"
:action-disabled="customerFormState.branchIndex !== -1"
id="form-basic-info-customer"
:create="customerFormState.dialogType === 'create'"
:create="false"
@edit="
(customerFormState.dialogType = 'edit'),
(customerFormState.readonly = false)
@ -1907,26 +1906,19 @@ const emptyCreateDialog = ref(false);
deleteCustomerById(customerFormState.editCustomerId)
"
:customer-type="customerFormData.customerType"
v-model:code="customerFormData.code"
v-model:registered-branch-id="customerFormData.registeredBranchId"
v-mode:customerName="customerFormData.customerName"
v-mode:registerName="customerFormData.registerName"
v-mode:citizenId="customerFormData.citizenId"
v-mode:legalPersonNo="customerFormData.legalPersonNo"
v-mode:businessType="customerFormData.businessType"
v-mode:jobPosition="customerFormData.jobPosition"
v-mode:telephoneNo="customerFormData.telephoneNo"
v-model:branch-options="registerAbleBranchOption"
v-model:first-name="customerFormData.firstName"
v-model:last-name="customerFormData.lastName"
v-model:first-name-en="customerFormData.firstNameEN"
v-model:last-name-en="customerFormData.lastNameEN"
v-model:name-prefix="customerFormData.namePrefix"
v-model:gender="customerFormData.gender"
v-model:birth-date="customerFormData.birthDate"
/>
</q-form>
<div class="row q-col-gutter-sm" id="form-branch-customer-branch">
<div
class="col-12 text-weight-bold text-body1 row items-center"
:style="{
opacity:
customerFormState.branchIndex !== -1 ? '0.5' : undefined,
}"
>
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
size="xs"
@ -1940,20 +1932,18 @@ const emptyCreateDialog = ref(false);
type="button"
class="q-ml-sm"
@click="customerFormStore.addCurrentCustomerBranch()"
v-if="
customerFormState.branchIndex === -1 &&
!!customerFormState.editCustomerId
"
v-if="false"
:disabled="!customerFormState.readonly"
/>
</div>
<template
v-for="(_, idx) in customerFormData.customerBranch"
:key="idx"
>
<!-- v-if="customerFormData.customerBranch" -->
<q-form
class="full-width"
v-if="customerFormData.customerBranch"
greedy
@submit.prevent="
async () => {
@ -1961,7 +1951,12 @@ const emptyCreateDialog = ref(false);
if (!customerFormState.editCustomerId) return;
if (customerFormData.customerType === 'CORP') {
filtdRequire.main = ['legalPersonNo', 'registerName'];
filtdRequire.main = [
'legalPersonNo',
'registerName',
'address',
'addressEN',
];
}
if (customerFormData.customerType === 'PERS') {
filtdRequire.main = ['citizenId'];
@ -1988,11 +1983,17 @@ const emptyCreateDialog = ref(false);
});
} else {
if (!customerFormData.customerBranch[idx].id) {
await customerStore.createBranch({
...customerFormData.customerBranch[idx],
customerId: customerFormState.editCustomerId,
id: undefined,
});
await customerFormStore.submitFormCustomer(
onCreateImageList,
);
customerFormState.readonly = true;
notify('create', $t('general.success'));
await fetchListCustomer();
// await customerStore.createBranch({
// ...customerFormData.customerBranch[idx],
// customerId: customerFormState.editCustomerId,
// id: undefined,
// });
} else {
await customerStore.editBranchById(
customerFormData.customerBranch[idx].id || '',
@ -2034,18 +2035,18 @@ const emptyCreateDialog = ref(false);
}
"
>
<!-- v-if="!!customerFormState.editCustomerId" -->
<!-- :action-disabled="
!customerFormState.readonly ||
(customerFormState.branchIndex !== -1 &&
customerFormState.branchIndex !== idx)
" -->
<EmployerFormBranch
v-if="!!customerFormState.editCustomerId"
:index="idx"
v-model:customer="customerFormData"
v-model:customer-branch="customerFormData.customerBranch[idx]"
:customer-type="customerFormData.customerType"
:customer-name="`${customerFormData.firstName} ${customerFormData.lastName}`"
:action-disabled="
!customerFormState.readonly ||
(customerFormState.branchIndex !== -1 &&
customerFormState.branchIndex !== idx)
"
:readonly="customerFormState.branchIndex !== idx"
@edit="() => (customerFormState.branchIndex = idx)"
@cancel="() => customerFormUndo(false)"

View file

@ -1,180 +1,462 @@
<script setup lang="ts">
import DatePicker from 'src/components/shared/DatePicker.vue';
import { formatNumberDecimal } from 'stores/utils';
import { QSelect } from 'quasar';
import { onMounted, ref, watch, capitalize } from 'vue';
import { formatNumberDecimal, selectFilterOptionRefMod } from 'stores/utils';
import { calculateAge, disabledAfterToday } from 'src/utils/datetime';
import useOptionStore from 'src/stores/options';
import DatePicker from 'src/components/shared/DatePicker.vue';
const props = defineProps<{
index: string;
code?: string;
readonly?: boolean;
prefixId?: string;
customerType?: 'PERS' | 'CORP';
}>();
const optionStore = useOptionStore();
// PERS
const citizenId = defineModel<string | undefined>('citizenId', {
required: true,
});
const prefixName = defineModel<string | null>('prefixName');
const firstName = defineModel<string>('firstName');
const lastName = defineModel<string>('lastName');
const firstNameEN = defineModel<string>('firstNameEN');
const lastNameEN = defineModel<string>('lastNameEN');
const gender = defineModel<string>('gender');
const birthDate = defineModel<Date | string | null>('birthDate');
// CORP
const customerName = defineModel<string>('customerName');
const legalPersonNo = defineModel<string | undefined>('legalPersonNo', {
required: true,
});
const branchCode = defineModel<string | undefined>('branchCode', {
required: true,
});
const customerCode = defineModel<string | undefined>('customerCode', {
required: true,
});
const registerName = defineModel<string | undefined>('registerName', {
required: true,
});
const registerNameEN = defineModel<string>('registerNameEn');
const registerNameEN = defineModel<string | undefined>('registerNameEN', {
required: true,
});
const registerDate = defineModel<Date | null>('registerDate');
const authorizedCapital = defineModel<string>('authorizedCapital', {
default: '0',
});
defineProps<{
index: string;
customerName?: string;
code?: string;
readonly?: boolean;
prefixId?: string;
customerType?: 'PERS' | 'CORP';
}>();
// both
const telephoneNo = defineModel<string>('telephoneNo');
const customerCode = defineModel<string | undefined>('customerCode', {
required: true,
});
const prefixNameOptions = ref<Record<string, unknown>[]>([]);
let prefixNameFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
const genderOptions = ref<Record<string, unknown>[]>([]);
let genderFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
onMounted(() => {
prefixNameFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption?.prefix),
prefixNameOptions,
'label',
);
genderFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption?.gender),
genderOptions,
'label',
);
});
watch(
() => optionStore.globalOption,
() => {
prefixNameFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption.prefix),
prefixNameOptions,
'label',
);
genderFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption.gender),
genderOptions,
'label',
);
},
);
watch(
() => prefixName.value,
(v) => {
if (props.readonly) return;
if (v === 'mr') gender.value = 'male';
else if (v !== '') gender.value = 'female';
},
);
</script>
<template>
<div class="row q-col-gutter-md">
<div class="row q-col-gutter-sm">
<template v-if="customerType === 'CORP'">
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-3"
:label="$t('customer.form.legalPersonNo')"
for="input-legal-person-no"
v-model="legalPersonNo"
/>
<div class="col-12 row q-col-gutter-sm">
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-5"
:label="$t('customer.form.employerName')"
for="input-legal-person-no"
v-model="customerName"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
<q-input
dense
outlined
hide-bottom-space
class="col-12 col-md-3"
for="input-branch-code"
:label="$t('customer.form.branchCode')"
:disable="!readonly"
:readonly="readonly"
:model-value="`${branchCode?.slice(0, -2) || '-'}${index.toString().padStart(2, '0')}`"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md"
:label="$t('customer.form.legalPersonCode')"
for="input-legal-person-code"
v-model="legalPersonNo"
/>
<q-input
dense
outlined
hide-bottom-space
class="col-12 col-md-3"
for="input-customer-code"
:disable="!readonly"
:readonly="readonly"
:label="$t('customer.form.customerCode')"
:model-value="legalPersonNo"
/>
<q-input
dense
outlined
hide-bottom-space
class="col-12 col-md"
for="input-customer-code"
:disable="!readonly"
:readonly="readonly"
:label="$t('customer.form.customerCode')"
:model-value="customerCode"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-3"
:label="$t('customer.form.legalPersonCode')"
for="input-legal-person-code"
:model-value="legalPersonNo"
/>
<q-input
dense
outlined
hide-bottom-space
class="col-12 col-md"
for="input-branch-code"
:label="$t('customer.form.branchCode')"
:disable="!readonly"
:readonly="readonly"
:model-value="`${branchCode?.slice(0, -2) || '-'}${index.toString().padStart(2, '0')}`"
/>
</div>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.registerName')"
for="input-register-name"
v-model="registerName"
/>
<div class="col-12 row q-col-gutter-sm">
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.registerName')"
for="input-register-name"
v-model="registerName"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.registerNameEN')"
for="input-register-name-en"
v-model="registerNameEN"
:rules="[(val) => /^[A-Za-z]+$/.test(val)]"
:error-message="$t('form.error.letterOnly')"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
label="Company name"
for="input-register-name-en"
v-model="registerNameEN"
:rules="[
(val: string) => !!val || $t('form.error.required'),
(val: string) =>
/^[A-Za-z]+$/.test(val) || $t('form.error.letterOnly'),
]"
/>
</div>
<q-input
dense
outlined
type="text"
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-3"
:label="$t('customer.form.authorizedCapital')"
for="input-authorized-capital"
:model-value="
!readonly
? authorizedCapital
: formatNumberDecimal(+authorizedCapital, 2)
"
@update:model-value="
(v) => {
authorizedCapital = `${v}`;
}
"
/>
<DatePicker
v-model="registerDate"
:id="`${prefixId}-input-register-date`"
:label="$t('customer.form.registerDate')"
:readonly="readonly"
clearable
/>
<div class="col-12 row q-col-gutter-sm">
<DatePicker
v-model="registerDate"
class="col-6 col-md-2"
:id="`${prefixId}-input-register-date`"
:label="$t('customer.form.registerDate')"
:readonly="readonly"
clearable
/>
<q-input
dense
outlined
type="text"
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-2"
:label="$t('customer.form.authorizedCapital')"
for="input-authorized-capital"
:model-value="
!readonly
? authorizedCapital
: formatNumberDecimal(+authorizedCapital, 2)
"
@update:model-value="
(v) => {
authorizedCapital = `${v}`;
}
"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.form.headQuarters.telephoneNo')"
for="input-first-name-en"
v-model="telephoneNo"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
</div>
</template>
<template v-if="customerType === 'PERS'">
<q-input
dense
outlined
:disable="index !== '0'"
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-3"
:label="$t('customer.form.cardNumber')"
for="input-legal-person-no"
v-model="citizenId"
/>
<div class="col-6 row q-col-gutter-sm">
<q-input
dense
outlined
hide-bottom-space
class="col-12 col-md-5"
for="input-customer-code"
:disable="!readonly"
:readonly="readonly"
:label="$t('customer.form.customerCode')"
:model-value="customerCode"
/>
<q-input
dense
outlined
:disable="!readonly"
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-3"
:label="$t('customer.form.branchCode')"
for="input-branch-code"
:model-value="`${branchCode?.slice(0, -2) || '-'}${index.toString().padStart(2, '0')}`"
/>
<q-input
dense
outlined
:disable="index !== '0'"
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-7"
:label="$t('customer.form.cardNumber')"
for="input-legal-person-no"
v-model="citizenId"
/>
</div>
<q-input
dense
outlined
:disable="!readonly"
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-3"
:label="$t('customer.form.customerCode')"
for="input-customer-code"
:model-value="citizenId"
/>
<div class="col-8 row q-col-gutter-sm">
<q-select
outlined
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-label="label"
option-value="value"
hide-dropdown-icon
class="col-md-2 col-6"
dense
:readonly="readonly"
:options="prefixNameOptions"
:for="`${prefixId}-select-prefix-name`"
:label="$t('personnel.form.prefixName')"
@filter="prefixNameFilter"
:model-value="readonly ? prefixName || '-' : prefixName"
@update:model-value="
(v) => (typeof v === 'string' ? (prefixName = v) : '')
"
@clear="prefixName = ''"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-input
:for="`${prefixId}-input-first-name`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col"
:label="$t('personnel.form.firstName')"
v-model="firstName"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
<q-input
:for="`${prefixId}-input-last-name`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col"
:label="$t('personnel.form.lastName')"
v-model="lastName"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
</div>
<div class="col-8 row q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-first-name`"
dense
outlined
hide-bottom-space
:readonly="readonly"
:disable="!readonly"
class="col-md-2 col-6"
label="Title"
:model-value="
readonly
? capitalize(prefixName || '') || '-'
: capitalize(prefixName || '')
"
@update:model-value="
(v) => (typeof v === 'string' ? (prefixName = v) : '')
"
@clear="prefixName = ''"
/>
<q-input
:for="`${prefixId}-input-first-name`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col"
label="Name"
v-model="firstNameEN"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
<q-input
:for="`${prefixId}-input-last-name`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col"
label="Surname"
v-model="lastNameEN"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
</div>
<div class="row col-8 q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-telephone`"
dense
outlined
:readonly="readonly"
class="col-md col-6"
:label="$t('form.telephone')"
:mask="readonly ? '' : '##########'"
:model-value="readonly ? telephoneNo || '-' : telephoneNo"
@update:model-value="
(v) => (typeof v === 'string' ? (telephoneNo = v) : '')
"
@clear="telephoneNo = ''"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
<q-select
outlined
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-label="label"
option-value="value"
class="col-md-2 col-6"
dense
:readonly="readonly"
:options="genderOptions"
:hide-dropdown-icon="readonly"
:for="`${prefixId}-select-gender`"
:label="$t('form.gender')"
@filter="genderFilter"
:model-value="readonly ? gender || '-' : gender"
@update:model-value="
(v) => (typeof v === 'string' ? (gender = v) : '')
"
@clear="gender = ''"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<DatePicker
v-model="birthDate"
class="col-md col-6"
:id="`${prefixId}-input-birth-date`"
:readonly="readonly"
:label="$t('form.birthDate')"
:disabled-dates="disabledAfterToday"
:rules="[
(val: string) =>
!!val ||
$t('form.error.selectField', { field: $t('form.birthDate') }),
]"
/>
<q-input
:for="`${prefixId}-input-age`"
:id="`${prefixId}-input-age`"
dense
outlined
readonly
:label="$t('personnel.age')"
class="col-md-2 col-12"
:model-value="
birthDate?.toString() === 'Invalid Date' ||
birthDate?.toString() === undefined
? ''
: calculateAge(birthDate)
"
/>
</div>
</template>
</div>
</template>

View file

@ -0,0 +1,35 @@
<script lang="ts" setup>
defineProps<{
readonly?: boolean;
prefixId?: string;
}>();
const authorizedName = defineModel<string>('authorizedName');
const authorizedNameEN = defineModel<string>('authorizedNameEN');
</script>
<template>
<div class="col-md-9 col-12 row q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-contact-name`"
:id="`${prefixId}-input-contact-name`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('customerBranch.tab.authorized')"
v-model="authorizedName"
/>
<q-input
:for="`${prefixId}-input-contact-name`"
:id="`${prefixId}-input-contact-name`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="`${$t('customerBranch.tab.authorized')} (EN)`"
v-model="authorizedNameEN"
/>
</div>
</template>

View file

@ -1,19 +1,10 @@
<script lang="ts" setup>
import { ref, watch, capitalize } from 'vue';
import { ref, watch } from 'vue';
import { QSelect } from 'quasar';
import { selectFilterOptionRefMod } from 'stores/utils';
import { getRole } from 'src/services/keycloak';
import useOptionStore from 'stores/options';
import { onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
const { locale } = useI18n();
import {
dateFormat,
calculateAge,
parseAndFormatDate,
disabledAfterToday,
} from 'src/utils/datetime';
import {
SaveButton,
@ -21,6 +12,7 @@ import {
DeleteButton,
UndoButton,
} from 'components/button';
withDefaults(
defineProps<{
prefixId?: string;
@ -43,20 +35,20 @@ defineEmits<{
}>();
const optionStore = useOptionStore();
const code = defineModel<string>('code', { required: true });
const namePrefix = defineModel<string | null>('namePrefix');
const birthDate = defineModel<Date | string | null>('birthDate');
const gender = defineModel<string>('gender');
const firstName = defineModel<string>('firstName', { required: true });
const lastName = defineModel<string>('lastName', { required: true });
const firstNameEN = defineModel<string>('firstNameEn', { required: true });
const lastNameEN = defineModel<string>('lastNameEn', { required: true });
const registeredBranchId = defineModel<string>('registeredBranchId', {
required: true,
});
const customerName = defineModel<string>('customerName');
const registerName = defineModel<string>('registerName');
const citizenId = defineModel<string>('citizenId');
const legalPersonNo = defineModel<string>('legalPersonNo');
const businessType = defineModel<'strinf'>('businessType');
const jobPosition = defineModel<'strinf'>('jobPosition');
const telephoneNo = defineModel<string>('telephoneNo');
const branchOptions = defineModel<{ id: string; name: string }[]>(
'branchOptions',
{ default: [] },
@ -87,69 +79,63 @@ watch(
},
);
const prefixNameOptions = ref<Record<string, unknown>[]>([]);
let prefixNameFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
// const prefixNameOptions = ref<Record<string, unknown>[]>([]);
// let prefixNameFilter: (
// value: string,
// update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
// ) => void;
const prefixNameEnOptions = ref<Record<string, unknown>[]>([]);
let prefixNameEnFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
// const genderOptions = ref<Record<string, unknown>[]>([]);
// let genderFilter: (
// value: string,
// update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
// ) => void;
const genderOptions = ref<Record<string, unknown>[]>([]);
let genderFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
// onMounted(() => {
// prefixNameFilter = selectFilterOptionRefMod(
// ref(optionStore.globalOption?.prefix),
// prefixNameOptions,
// 'label',
// );
// genderFilter = selectFilterOptionRefMod(
// ref(optionStore.globalOption?.gender),
// genderOptions,
// 'label',
// );
// });
onMounted(() => {
prefixNameFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption?.prefix),
prefixNameOptions,
'label',
);
genderFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption?.gender),
genderOptions,
'label',
);
});
// watch(
// () => optionStore.globalOption,
// () => {
// prefixNameFilter = selectFilterOptionRefMod(
// ref(optionStore.globalOption.prefix),
// prefixNameOptions,
// 'label',
// );
// genderFilter = selectFilterOptionRefMod(
// ref(optionStore.globalOption.gender),
// genderOptions,
// 'label',
// );
// },
// );
watch(
() => optionStore.globalOption,
() => {
prefixNameFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption.prefix),
prefixNameOptions,
'label',
);
genderFilter = selectFilterOptionRefMod(
ref(optionStore.globalOption.gender),
genderOptions,
'label',
);
},
);
// watch(
// () => namePrefix.value,
// (v) => {
// if (v === 'mr') gender.value = 'male';
// else gender.value = 'female';
// },
// );
watch(
() => namePrefix.value,
(v) => {
if (v === 'mr') gender.value = 'male';
else gender.value = 'female';
},
);
function formatCode(input: string | undefined, type: 'code' | 'number') {
if (!input) return;
return input.slice(...(type === 'code' ? [0, -6] : [-6]));
}
// function formatCode(input: string | undefined, type: 'code' | 'number') {
// if (!input) return;
// return input.slice(...(type === 'code' ? [0, -6] : [-6]));
// }
</script>
<template>
<div class="row q-col-gutter-sm q-mb-sm">
<div class="row q-col-gutter-sm">
<div
v-if="!hideAction"
class="col-12 text-weight-bold text-body1 row items-center"
@ -162,8 +148,18 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
name="mdi-office-building-outline"
style="background-color: var(--surface-3)"
/>
<span>{{ $t('form.field.basicInformation') }}</span>
<EditButton
<span>
{{
$t('general.information', {
msg: `${$t('customer.employer')}${
customerType === 'CORP'
? $t('customer.employerLegalEntity')
: $t('customer.employerNaturalPerson')
}`,
})
}}
</span>
<!-- <EditButton
icon-only
v-if="readonly && !create"
type="button"
@ -193,10 +189,540 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
@click="$emit('save')"
type="submit"
:disabled="actionDisabled"
/>
/> -->
</div>
<div class="col-12 row q-col-gutter-sm">
<div class="col-12 row q-col-gutter-sm">
<q-select
outlined
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
dense
class="col-6"
option-value="id"
input-debounce="0"
option-label="name"
v-model="registeredBranchId"
:readonly="readonly"
:options="filteredBranchOptions"
:hide-dropdown-icon="readonly"
:label="$t('customer.form.registeredBranch')"
:for="`${prefixId}-input-source-nationality`"
:rules="[
(val) => {
const roles = getRole() || [];
return (
['admin', 'system', 'head_of_admin'].some((v) =>
roles.includes(v),
) ||
!!val ||
$t('form.error.required')
);
},
]"
@filter="branchFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
</div>
<div
v-if="customerType === 'CORP' && !create"
class="row col-12 q-col-gutter-sm"
>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.customerName')"
for="input-first-name"
v-model="registerName"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('general.taxNo')"
for="input-first-name-en"
v-model="legalPersonNo"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.table.businessTypePure')"
for="input-first-name-en"
v-model="businessType"
/>
</div>
<div
v-if="customerType === 'PERS' && !create"
class="row col-12 q-col-gutter-sm"
>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.employerName')"
for="input-first-name"
v-model="customerName"
/>
<q-input
outlined
class="col-md-3 col-6"
hide-bottom-space
v-model="citizenId"
mask="#############"
:readonly="readonly"
dense
:label="$t('personnel.form.citizenId')"
for="input-citizen-id"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.table.businessTypePure')"
for="input-first-name-en"
v-model="businessType"
/>
</div>
<div v-if="!create" class="row col-12 q-col-gutter-sm">
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-5"
:label="$t('customer.form.jobPosition')"
for="input-first-name-en"
v-model="jobPosition"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.form.headQuarters.telephoneNo')"
for="input-first-name-en"
v-model="telephoneNo"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
</div>
</div>
<!-- <div v-if="customerType === 'CORP'" class="col-12 row q-col-gutter-sm">
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.customerName')"
for="input-first-name"
v-model="customerName"
:rules="[(val: string) => !!val || $t('form.error.required')]"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-6"
:label="$t('customer.form.customerNameEN')"
for="input-first-name-en"
v-model="customerNameEN"
:rules="[
(val: string) => !!val || $t('form.error.required'),
(val: string) =>
/^[A-Za-z]+$/.test(val) || $t('form.error.letterOnly'),
]"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('general.taxNo')"
for="input-first-name-en"
v-model="taxNo"
mask="#############"
:rules="[
(val) => (val && val.length > 0) || $t('form.error.required'),
(val) =>
(val && val.length === 13 && /[0-9]+/.test(val)) ||
$t('form.error.invalidCustomeMessage', {
msg: $t('form.error.requireLength', { msg: 13 }),
}),
]"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.table.businessTypePure')"
for="input-first-name-en"
v-model="businessType"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.form.jobPosition')"
for="input-first-name-en"
v-model="jobPosition"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.form.headQuarters.telephoneNo')"
for="input-first-name-en"
v-model="telephoneNo"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
</div>
<div v-if="customerType === 'PERS'" class="col-12 row q-col-gutter-sm">
<div class="col-9 row q-col-gutter-sm">
<q-select
outlined
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
dense
class="col-12"
option-value="id"
input-debounce="0"
option-label="name"
v-model="registeredBranchId"
:readonly="readonly"
:options="filteredBranchOptions"
:hide-dropdown-icon="readonly"
:label="$t('customer.form.registeredBranch')"
:for="`${prefixId}-input-source-nationality`"
:rules="[
(val) => {
const roles = getRole() || [];
return (
['admin', 'system', 'head_of_admin'].some((v) =>
roles.includes(v),
) ||
!!val ||
$t('form.error.required')
);
},
]"
@filter="branchFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-select
outlined
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-label="label"
option-value="value"
hide-dropdown-icon
class="col-12 col-md-2"
dense
:readonly="readonly"
:options="prefixNameOptions"
:for="`${prefixId}-select-prefix-name`"
:label="$t('form.prefixName')"
@filter="prefixNameFilter"
:model-value="readonly ? namePrefix || '-' : namePrefix"
@update:model-value="
(v) => {
typeof v === 'string' ? (namePrefix = v) : '';
}
"
@clear="namePrefix = ''"
:rules="[
(val) => {
const roles = getRole() || [];
return !!val || $t('form.error.required');
},
]"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-5"
:label="$t('customer.form.firstName')"
for="input-first-name"
v-model="firstName"
:rules="[
(val) => {
const roles = getRole() || [];
return !!val || $t('form.error.required');
},
]"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-5"
:label="$t('customer.form.lastName')"
for="input-last-name"
v-model="lastName"
:rules="[
(val) => {
const roles = getRole() || [];
return !!val || $t('form.error.required');
},
]"
/>
<q-input
dense
outlined
:disable="!readonly"
readonly
hide-bottom-space
class="col-12 col-md-2"
label="Title"
for="input-prefix-name-en"
:model-value="
readonly
? capitalize(namePrefix || '') || '-'
: capitalize(namePrefix || '')
"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-5"
label="Name"
for="input-first-name-en"
v-model="firstNameEN"
:rules="[
(val: string) => !!val || $t('form.error.required'),
(val: string) =>
/^[A-Za-z]+$/.test(val) || $t('form.error.letterOnly'),
]"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-12 col-md-5"
label="Surname"
for="input-last-name-en"
v-model="lastNameEN"
:rules="[
(val: string) => !!val || $t('form.error.required'),
(val: string) =>
/^[A-Za-z]+$/.test(val) || $t('form.error.letterOnly'),
]"
/>
<q-input
outlined
class="col-md-5 col-12"
hide-bottom-space
v-model="lastNameEN"
mask="#############"
:readonly="readonly"
dense
:label="$t('personnel.form.citizenId')"
:rules="[
(val) => (val && val.length > 0) || $t('form.error.required'),
(val) =>
(val && val.length === 13 && /[0-9]+/.test(val)) ||
$t('form.error.invalidCustomeMessage', {
msg: $t('form.error.requireLength', { msg: 13 }),
}),
]"
for="input-citizen-id"
/>
<q-select
outlined
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-label="label"
option-value="value"
class="col-md-2 col-6"
dense
:readonly="readonly"
:options="genderOptions"
:hide-dropdown-icon="readonly"
:for="`${prefixId}-select-gender`"
:label="$t('form.gender')"
@filter="genderFilter"
:model-value="readonly ? gender || '-' : gender"
@update:model-value="
(v) => (typeof v === 'string' ? (gender = v) : '')
"
@clear="gender = ''"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<DatePicker
v-model="birthDate"
class="col-md col-6"
:id="`${prefixId}-input-birth-date`"
:readonly="readonly"
:label="$t('form.birthDate')"
:disabled-dates="disabledAfterToday"
:rules="[
(val: string) =>
!!val ||
$t('form.error.selectField', { field: $t('form.birthDate') }),
]"
/>
<q-input
:for="`${prefixId}-input-age`"
:id="`${prefixId}-input-age`"
dense
outlined
:label="$t('personnel.age')"
class="col-md col-12"
:model-value="
birthDate?.toString() === 'Invalid Date' ||
birthDate?.toString() === undefined
? ''
: calculateAge(birthDate)
"
/>
</div>
<div class="row col-12 q-col-gutter-sm">
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md"
:label="$t('customer.table.businessTypePure')"
for="input-first-name-en"
v-model="firstNameEN"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md"
:label="$t('customer.form.jobPosition')"
for="input-first-name-en"
v-model="firstNameEN"
/>
<q-input
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
:label="$t('customer.form.headQuarters.telephoneNo')"
for="input-first-name-en"
v-model="firstNameEN"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
</div>
</div> -->
<!-- <div class="col-12 row q-col-gutter-sm">
<q-select
outlined
clearable
@ -482,6 +1008,6 @@ function formatCode(input: string | undefined, type: 'code' | 'number') {
: calculateAge(birthDate)
"
/>
</div>
</div> -->
</div>
</template>

View file

@ -5,6 +5,7 @@ import EmployerFormBusiness from './EmployerFormBusiness.vue';
import EmployerFormContact from './EmployerFormContact.vue';
import { CustomerCreate } from 'stores/customer/types';
import EmployerFormAbout from './EmployerFormAbout.vue';
import EmployerFormAuthorized from './EmployerFormAuthorized.vue';
import { useCustomerForm } from 'src/pages/03_customer-management/form';
const customerFormStore = useCustomerForm();
@ -68,7 +69,7 @@ withDefaults(
? $t('customer.form.headQuarters.title')
: $t('customer.form.branch.title', { name: index || 0 })
}}
<EditButton
<!-- <EditButton
icon-only
v-if="readonly"
@click="$emit('edit')"
@ -90,11 +91,12 @@ withDefaults(
type="button"
class="q-ml-auto"
:disabled="actionDisabled"
/>
/> -->
<!-- v-if="!readonly" -->
<SaveButton
icon-only
v-if="!readonly"
@click="$emit('save')"
class="q-ml-auto"
type="submit"
:disabled="actionDisabled"
/>
@ -109,10 +111,16 @@ withDefaults(
class="bordered-b"
active-color="primary"
no-caps
style="color: hsl(var(--text-mute))"
>
<q-tab name="main" :label="$t('customerBranch.tab.main')" />
<q-tab name="address" :label="$t('customerBranch.tab.address')" />
<q-tab name="business" :label="$t('customerBranch.tab.business')" />
<q-tab
v-if="customerType === 'CORP'"
name="authorized"
:label="$t('customerBranch.tab.authorized')"
/>
<q-tab name="address" :label="$t('customerBranch.tab.address')" />
<q-tab name="contact" :label="$t('customerBranch.tab.contact')" />
<q-tab name="attachment" :label="$t('customerBranch.tab.attachment')" />
</q-tabs>
@ -122,37 +130,23 @@ withDefaults(
:index="index.toString()"
:readonly="readonly"
:customer-type="customerType"
:customer-name="customerName"
v-model:citizen-id="item.citizenId"
v-model:id="item.id"
v-model:legal-person-no="item.legalPersonNo"
v-model:branch-code="item.code"
v-model:customer-code="customer.code"
v-model:register-company-name="item.registerCompanyName"
v-model:register-name="item.registerName"
v-model:register-name-en="item.registerNameEN"
v-model:register-date="item.registerDate"
v-model:authorized-capital="item.authorizedCapital"
/>
</q-tab-panel>
<q-tab-panel name="address">
<AddressForm
use-work-place
:prefix-id="prefixId || 'employer'"
hide-title
dense
:readonly="readonly"
outlined
:title="$t('form.address')"
v-model:workplace="item.workplace"
v-model:workplace-en="item.workplaceEN"
v-model:address="item.address"
v-model:addressEN="item.addressEN"
v-model:province-id="item.provinceId"
v-model:district-id="item.districtId"
v-model:sub-district-id="item.subDistrictId"
:addressTitle="$t('form.address')"
:addressTitleEN="$t('form.address', { suffix: '(EN)' })"
v-model:prefixName="item.namePrefix"
v-model:firstName="item.firstName"
v-model:lastName="item.lastName"
v-model:firstNameEN="item.firstNameEN"
v-model:lastNameEN="item.lastNameEN"
v-model:gender="item.gender"
v-model:birthDate="item.birthDate"
v-model:customerName="item.customerName"
v-model:legalPersonNo="item.legalPersonNo"
v-model:branchCode="item.branchCode"
v-model:registerName="item.registerName"
v-model:registerNameEN="item.registerNameEN"
v-model:registerDate="item.registerDate"
v-model:authorizedCapital="item.authorizedCapital"
v-model:telephoneNo="item.telephoneNo"
v-model:customerCode="item.customerCode"
/>
</q-tab-panel>
<q-tab-panel name="business">
@ -161,15 +155,48 @@ withDefaults(
outlined
:prefix-id="prefixId || 'employer'"
:readonly="readonly"
v-model:employment-office="item.employmentOffice"
v-model:bussiness-type="item.businessType"
v-model:bussiness-type-en="item.businessTypeEN"
v-model:job-position="item.jobPosition"
v-model:job-position-en="item.jobPositionEN"
v-model:job-description="item.jobDescription"
v-model:sale-employee="item.saleEmployee"
v-model:pay-date="item.payDate"
v-model:pay-date-e-n="item.payDateEN"
v-model:wage-rate="item.wageRate"
v-model:wage-rate-text="item.wageRateText"
/>
</q-tab-panel>
<q-tab-panel v-if="customerType === 'CORP'" name="authorized">
<EmployerFormAuthorized
:prefix-id="prefixId || 'employer'"
:readonly="readonly"
v-model:authorized-name="item.authorizedName"
v-model:authorized-name-e-n="item.authorizedNameEN"
/>
</q-tab-panel>
<q-tab-panel name="address">
<AddressForm
:prefix-id="prefixId || 'employer'"
hide-title
dense
outlined
use-employment
:readonly="readonly"
:title="$t('form.address')"
v-model:homeCode="item.homeCode"
v-model:employmentOffice="item.employmentOffice"
v-model:employmentOfficeEN="item.employmentOfficeEN"
v-model:address="item.address"
v-model:addressEN="item.addressEN"
v-model:street="item.street"
v-model:streetEN="item.streetEN"
v-model:moo="item.moo"
v-model:mooEN="item.mooEN"
v-model:soi="item.soi"
v-model:soiEN="item.soiEN"
v-model:province-id="item.provinceId"
v-model:district-id="item.districtId"
v-model:sub-district-id="item.subDistrictId"
:addressTitle="$t('form.address')"
:addressTitleEN="$t('form.address', { suffix: '(EN)' })"
/>
</q-tab-panel>
<q-tab-panel name="contact">
@ -177,7 +204,9 @@ withDefaults(
:readonly="readonly"
v-model:contactName="item.contactName"
v-model:email="item.email"
v-model:telephone="item.telephoneNo"
v-model:contactTel="item.contactTel"
v-model:officeTel="item.officeTel"
v-model:agent="item.agent"
/>
</q-tab-panel>
<q-tab-panel name="attachment">

View file

@ -1,31 +1,25 @@
<script setup lang="ts">
import { selectFilterOptionRefMod } from 'stores/utils';
import { dateFormat, parseAndFormatDate } from 'src/utils/datetime';
import { onMounted, watch } from 'vue';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import DatePicker from 'src/components/shared/DatePicker.vue';
const { locale } = useI18n({ useScope: 'global' });
const employmentOffice = defineModel<string>('employmentOffice');
const bussinessType = defineModel<string>('bussinessType');
const jobPosition = defineModel<string>('jobPosition');
const bussinessTypeEN = defineModel<string>('bussinessTypeEn');
const jobPositionEN = defineModel<string>('jobPositionEn');
const jobDescription = defineModel<string>('jobDescription');
const payDate = defineModel<Date | null | string>('payDate');
const wageRate = defineModel<number>('wageRate');
const saleEmployee = defineModel<string>('saleEmployee');
const rawOption = ref();
const bussinessType = defineModel<string>('bussinessType');
const jobPosition = defineModel<string>('jobPosition');
const jobDescription = defineModel<string>('jobDescription');
const payDate = defineModel<string>('payDate');
const payDateEN = defineModel<string>('payDateEN');
const wageRate = defineModel<number>('wageRate');
const wageRateText = defineModel<string>('wageRateText');
const typeBusinessOption = ref([]);
const typeBusinessENOption = ref([]);
const jobPositionOption = ref([]);
const jobPositionENOption = ref([]);
defineProps<{
title?: string;
@ -38,6 +32,8 @@ defineProps<{
onMounted(async () => {
const resultOption = await fetch('/option/option.json');
rawOption.value = await resultOption.json();
typeBusinessENOption.value = rawOption.value.eng.businessType;
jobPositionENOption.value = rawOption.value.eng.position;
if (locale.value === 'eng') {
typeBusinessOption.value = rawOption.value.eng.businessType;
@ -48,20 +44,31 @@ onMounted(async () => {
jobPositionOption.value = rawOption.value.tha.position;
}
});
watch(typeBusinessOption, () => {
watch([typeBusinessOption, typeBusinessENOption], () => {
typeBusinessFilter = selectFilterOptionRefMod(
typeBusinessOption,
typeBusinessOptions,
'label',
);
typeBusinessENFilter = selectFilterOptionRefMod(
typeBusinessENOption,
typeBusinessENOptions,
'label',
);
});
watch(jobPositionOption, () => {
watch([jobPositionOption, jobPositionENOption], () => {
jobPositionFilter = selectFilterOptionRefMod(
jobPositionOption,
jobPositionOptions,
'label',
);
jobPositionENFilter = selectFilterOptionRefMod(
jobPositionENOption,
jobPositionENOptions,
'label',
);
});
const typeBusinessOptions = ref<Record<string, unknown>[]>([]);
@ -77,21 +84,23 @@ let jobPositionFilter = selectFilterOptionRefMod(
jobPositionOptions,
'label',
);
const typeBusinessENOptions = ref<Record<string, unknown>[]>([]);
let typeBusinessENFilter = selectFilterOptionRefMod(
typeBusinessENOption,
typeBusinessENOptions,
'label',
);
const jobPositionENOptions = ref<Record<string, unknown>[]>([]);
let jobPositionENFilter = selectFilterOptionRefMod(
jobPositionENOption,
jobPositionENOptions,
'label',
);
</script>
<template>
<div class="col-12 row q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-employment-office`"
:id="`${prefixId}-input-employment-office`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-12"
:label="$t('form.address')"
v-model="employmentOffice"
/>
<q-select
outlined
clearable
@ -121,18 +130,36 @@ let jobPositionFilter = selectFilterOptionRefMod(
</q-item>
</template>
</q-select>
<q-input
<q-select
:for="`${prefixId}-input-bussiness-type-en`"
:id="`${prefixId}-input-bussiness-type-en`"
:dense="dense"
:label="`${$t('customer.form.businessType')} (EN)`"
outlined
:readonly="readonly"
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-value="value"
option-label="label"
v-model="bussinessType"
class="col-md-6 col-12"
:label="$t('customer.form.businessTypeEN')"
v-model="bussinessTypeEN"
/>
:dense="dense"
:readonly="readonly"
:options="typeBusinessENOptions"
@filter="typeBusinessENFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-select
outlined
@ -164,19 +191,36 @@ let jobPositionFilter = selectFilterOptionRefMod(
</template>
</q-select>
<q-input
<q-select
outlined
clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
input-debounce="0"
option-value="value"
option-label="label"
v-model="jobPosition"
class="col-md-6 col-12"
:dense="dense"
:readonly="readonly"
:label="`${$t('customer.form.jobPosition')} (EN)`"
:options="jobPositionENOptions"
:for="`${prefixId}-input-job-position-en`"
:id="`${prefixId}-input-job-position-en`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('customer.form.jobPositionEN')"
v-model="jobPositionEN"
:rules="[(val) => /^[A-Za-z]+$/.test(val)]"
:error-message="$t('form.error.letterOnly')"
/>
@filter="jobPositionENFilter"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
{{ $t('general.noData') }}
</q-item-section>
</q-item>
</template>
</q-select>
<q-input
:for="`${prefixId}-input-job-description`"
@ -190,12 +234,28 @@ let jobPositionFilter = selectFilterOptionRefMod(
v-model="jobDescription"
/>
<DatePicker
:id="`${prefixId}-date-picker-pay-date`"
v-model="payDate"
:label="$t('customer.form.payDay')"
<q-input
:for="`${prefixId}-input-pay-rate`"
:id="`${prefixId}-input-pay-rate`"
:dense="dense"
outlined
:readonly="readonly"
clearable
hide-bottom-space
class="col-md-3 col-6"
:label="$t('customer.form.payDay')"
v-model="payDate"
/>
<q-input
:for="`${prefixId}-input-pay-rate`"
:id="`${prefixId}-input-pay-rate`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-3 col-6"
label="Pay day"
v-model="payDateEN"
/>
<q-input
@ -211,15 +271,15 @@ let jobPositionFilter = selectFilterOptionRefMod(
/>
<q-input
:for="`${prefixId}-input-sales-person`"
:id="`${prefixId}-input-sales-person`"
:for="`${prefixId}-input-pay-rate`"
:id="`${prefixId}-input-pay-rate`"
:dense="dense"
outlined
:readonly="readonly"
hide-bottom-space
class="col-6"
:label="$t('customer.form.salesPerson')"
v-model="saleEmployee"
class="col-md-3 col-6"
:label="`${$t('customer.form.payRate')} (Text)`"
v-model="wageRateText"
/>
</div>
</template>

View file

@ -4,12 +4,14 @@ defineProps<{
prefixId?: string;
}>();
const contactName = defineModel<string>('contactName');
const mail = defineModel<string>('email');
const telephone = defineModel<string>('telephone');
const email = defineModel<string>('email');
const contactTel = defineModel<string>('contactTel');
const officeTel = defineModel<string>('officeTel');
const agent = defineModel<string>('agent');
</script>
<template>
<div class="col-md-9 col-12 row q-col-gutter-md">
<div class="col-md-9 col-12 row q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-contact-name`"
:id="`${prefixId}-input-contact-name`"
@ -41,8 +43,17 @@ const telephone = defineModel<string>('telephone');
$t('form.error.invalid'),
]
"
v-model="mail"
/>
v-model="email"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-email-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
<q-input
:for="`${prefixId}-input-telephone`"
:id="`${prefixId}-input-telephone`"
@ -52,7 +63,49 @@ const telephone = defineModel<string>('telephone');
hide-bottom-space
class="col-md-6 col-12"
:label="$t('form.telephone')"
v-model="telephone"
v-model="contactTel"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
<q-input
:for="`${prefixId}-input-telephone`"
:id="`${prefixId}-input-telephone`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('customer.form.headQuarters.telephoneNo')"
v-model="officeTel"
>
<template #prepend>
<q-icon
size="xs"
name="mdi-phone-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
<q-input
:for="`${prefixId}-input-telephone`"
:id="`${prefixId}-input-telephone`"
dense
outlined
:readonly="readonly"
hide-bottom-space
class="col-md-6 col-12"
:label="$t('customer.form.agent')"
v-model="agent"
/>
</div>
</template>

View file

@ -18,20 +18,20 @@ export const useCustomerForm = defineStore('form-customer', () => {
const branchStore = useMyBranch();
const defaultFormData: CustomerCreate = {
code: '',
// code: '',
// namePrefix: '',
// firstName: '',
// lastName: '',
// firstNameEN: '',
// lastNameEN: '',
// gender: '',
// birthDate: new Date(),
customerBranch: [],
selectedImage: '',
status: 'CREATED',
customerType: 'CORP',
namePrefix: '',
firstName: '',
lastName: '',
firstNameEN: '',
lastNameEN: '',
gender: '',
birthDate: new Date(),
registeredBranchId: branchStore.currentMyBranch?.id || '',
customerBranch: [],
image: null,
selectedImage: '',
};
let resetFormData = structuredClone(defaultFormData);
@ -138,9 +138,9 @@ export const useCustomerForm = defineStore('form-customer', () => {
state.value.defaultCustomerImageUrl = `${baseUrl}/customer/${id}/image/${data.selectedImage}`;
resetFormData.registeredBranchId = data.registeredBranchId;
resetFormData.code = data.code || '';
resetFormData.status = data.status;
resetFormData.customerType = data.customerType;
resetFormData.code = data.code || '';
resetFormData.namePrefix = data.namePrefix;
resetFormData.firstName = data.firstName;
resetFormData.lastName = data.lastName;
@ -160,7 +160,8 @@ export const useCustomerForm = defineStore('form-customer', () => {
districtId: v.districtId,
subDistrictId: v.subDistrictId,
wageRate: v.wageRate,
payDate: new Date(v.payDate), // Convert the string to a Date object
payDate: v.payDate, // Convert the string to a Date object
payDateEN: v.payDateEN,
saleEmployee: v.saleEmployee,
jobDescription: v.jobDescription,
jobPositionEN: v.jobPositionEN,
@ -208,57 +209,77 @@ export const useCustomerForm = defineStore('form-customer', () => {
currentFormData.value = structuredClone(resetFormData);
}
function addCurrentCustomerBranch() {
async function addCurrentCustomerBranch() {
if (currentFormData.value.customerBranch?.some((v) => !v.id)) return;
currentFormData.value.customerBranch?.push({
id: '',
code:
currentFormData.value.customerBranch.length !== 0
? currentFormData.value.customerBranch?.[0].code === null
? ''
: currentFormData.value.customerBranch?.[0].code
: '',
customerCode: '',
provinceId: '',
districtId: '',
subDistrictId: '',
wageRate: 0,
payDate: new Date(), // Convert the string to a Date object
saleEmployee: '',
jobDescription: '',
jobPositionEN: '',
jobPosition: '',
businessTypeEN: '',
businessType: '',
employmentOffice: '',
telephoneNo: '',
email: '',
addressEN: '',
address: '',
workplaceEN: '',
workplace: '',
status: 'CREATED',
customerId: '',
citizenId:
branchCode:
currentFormData.value.customerBranch.length !== 0
? currentFormData.value.customerBranch?.[0].citizenId === null
? currentFormData.value.customerBranch?.[0].branchCode === null
? ''
: currentFormData.value.customerBranch?.[0].citizenId
: currentFormData.value.customerBranch?.[0].branchCode
: '',
authorizedCapital: '',
registerDate: new Date(), // Convert the string to a Date object
registerNameEN: '',
registerName: '',
customerCode: '',
legalPersonNo:
currentFormData.value.customerBranch.length !== 0
? currentFormData.value.customerBranch?.[0].legalPersonNo === null
? ''
: currentFormData.value.customerBranch?.[0].legalPersonNo
: '',
registerCompanyName: '',
citizenId:
currentFormData.value.customerBranch.length !== 0
? currentFormData.value.customerBranch?.[0].citizenId === null
? ''
: currentFormData.value.customerBranch?.[0].citizenId
: '',
namePrefix: '',
firstName: '',
lastName: '',
firstNameEN: '',
lastNameEN: '',
telephoneNo: '',
gender: '',
birthDate: '',
businessType: '',
jobPosition: '',
jobDescription: '',
payDate: '',
payDateEN: '',
wageRate: 0,
wageRateText: '',
homeCode: '',
employmentOffice: '',
employmentOfficeEN: '',
address: '',
addressEN: '',
street: '',
streetEN: '',
moo: '',
mooEN: '',
soi: '',
soiEN: '',
provinceId: '',
districtId: '',
subDistrictId: '',
contactName: '',
email: '',
contactTel: '',
officeTel: '',
agent: '',
status: 'CREATED',
customerName: '',
registerName: '',
registerNameEN: '',
registerDate: null,
authorizedCapital: '',
authorizedName: '',
authorizedNameEN: '',
file: [],
});
state.value.branchIndex =
@ -329,7 +350,8 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
districtId: '',
subDistrictId: '',
wageRate: 0,
payDate: new Date(), // Convert the string to a Date object
payDate: '',
payDateEN: '',
saleEmployee: '',
jobDescription: '',
jobPositionEN: '',
@ -395,7 +417,8 @@ export const useCustomerBranchForm = defineStore('form-customer-branch', () => {
districtId: _data.districtId,
subDistrictId: _data.subDistrictId,
wageRate: _data.wageRate,
payDate: new Date(_data.payDate), // Convert the string to a Date object
payDate: _data.payDate, // Convert the string to a Date object
payDateEN: _data.payDateEN,
saleEmployee: _data.saleEmployee,
jobDescription: _data.jobDescription,
jobPositionEN: _data.jobPositionEN,

View file

@ -333,15 +333,24 @@ const useCustomerStore = defineStore('api-customer', () => {
transactionId?: string;
},
) {
const { code, customerBranch, image, ...payload } = data;
if (data.customerBranch) {
if (data.customerBranch[0].citizenId) {
console.log('1');
delete data.customerBranch[0]['authorizedNameEN'];
delete data.customerBranch[0]['authorizedName'];
delete data.customerBranch[0]['authorizedCapital'];
delete data.customerBranch[0]['registerDate'];
delete data.customerBranch[0]['registerNameEN'];
delete data.customerBranch[0]['registerName'];
delete data.customerBranch[0]['legalPersonNo'];
} else {
delete data.customerBranch[0]['citizenId'];
}
if (!data.customerBranch[0].birthDate)
delete data.customerBranch[0]['birthDate'];
}
// const attachment = payload.customerBranch?.map((v) => v.file);
// if (payload.customerBranch?.length) {
// for (let i = 0; i < payload.customerBranch?.length; i++) {
// delete payload.customerBranch[i].file;
// }
// }
const { customerBranch, image, ...payload } = data;
const res = await api.post<
Customer & {
@ -351,7 +360,18 @@ const useCustomerStore = defineStore('api-customer', () => {
}
>(
'/customer',
{ ...payload, selectedImage: imgList.selectedImage },
{
...payload,
branch: data.customerBranch?.map((v) => ({
...v,
file: undefined,
branchCode: undefined,
id: undefined,
customerId: undefined,
customerCode: undefined,
})),
selectedImage: imgList.selectedImage,
},
{
headers: {
'X-Session-Id': flow?.sessionId,
@ -361,21 +381,6 @@ const useCustomerStore = defineStore('api-customer', () => {
},
);
// await Promise.allSettled([
// ...res.data.branch.map(async (v, i) => {
// const fileList = attachment?.[i];
// if (fileList)
// return await addBranchAttachment(v.id, { file: fileList });
// }),
// image &&
// (await api
// .put(`/customer/${res.data.id}/image`, image, {
// headers: { 'Content-Type': image?.type },
// onUploadProgress: (e) => console.log(e),
// })
// .catch((e) => console.error(e)));
// ]);
if (imgList.list.length > 0 && res.data.id) {
for (let index = 0; index < imgList.list.length; index++) {
const imgFile = imgList.list[index].imgFile;

View file

@ -34,20 +34,16 @@ export type CustomerBranch = {
contactName: string;
wageRate: number;
payDate: string;
saleEmployee: string;
payDateEN: string;
jobDescription: string;
jobPositionEN: string;
jobPosition: string;
businessTypeEN: string;
businessType: string;
employmentOffice: string;
workplaceEN: string;
workplace: string;
authorizedCapital: string;
registerDate: string;
registerDate: Date | null;
registerNameEN: string;
registerName: string;
legalPersonNo: string;
legalPersonNo?: string;
citizenId: string;
updatedByUserId: string;
createdByUserId: string;
@ -76,101 +72,81 @@ export type CustomerBranch = {
};
export type CustomerBranchCreate = {
code?: string;
customerCode?: string;
contactName: string;
customerId: string;
legalPersonNo?: string;
citizenId?: string;
namePrefix?: string;
firstName?: string;
lastName?: string;
firstNameEN?: string;
lastNameEN?: string;
telephoneNo?: string;
gender?: string;
birthDate?: string;
businessType: string;
jobPosition: string;
jobDescription: string;
payDate?: string;
payDateEN?: string;
wageRate: number;
wageRateText: string;
homeCode: string;
employmentOffice: string;
employmentOfficeEN?: string;
address: string;
addressEN?: string;
street: string;
streetEN?: string;
moo?: string;
mooEN?: string;
soi?: string;
soiEN?: string;
provinceId: string;
districtId: string;
subDistrictId: string;
wageRate: number;
payDate: Date | null;
saleEmployee: string;
jobDescription: string;
jobPositionEN: string;
jobPosition: string;
businessTypeEN: string;
businessType: string;
employmentOffice: string;
telephoneNo: string;
contactName: string;
email: string;
addressEN: string;
address: string;
workplaceEN: string;
workplace: string;
status: Status | undefined;
customerId: string;
citizenId?: string;
authorizedCapital?: string;
registerDate?: Date | null;
registerNameEN?: string;
contactTel?: string;
officeTel?: string;
agent?: string;
status: Status;
customerName?: string;
registerName?: string;
legalPersonNo?: string;
registerCompanyName: string;
statusSave?: boolean;
registerNameEN?: string;
registerDate?: Date | null;
authorizedCapital?: string;
authorizedName?: string;
authorizedNameEN?: string;
file?: {
name?: string;
group?: string;
url?: string;
file?: File;
}[];
// id?: string;
// code?: string;
// provinceId?: string | null;
// branchNo?: number;
// address: string;
// addressEN: string;
// districtId?: string | null;
// subDistrictId?: string | null;
// zipCode: string;
// email: string;
// telephoneNo: string;
// status?: Status;
// name: string;
// taxNo?: string | null;
// nameEN: string;
// legalPersonNo: string;
// registerName: string;
// registerDate: Date | null;
// authorizedCapital: string;
// employmentOffice: string;
// bussinessType: string;
// bussinessTypeEN: string;
// jobPosition: string;
// jobPositionEN: string;
// jobDescription: string;
// saleEmployee: string;
// payDate: Date;
// wageRate: number;
// file?: File[];
// statusSave?: boolean;
};
export type CustomerCreate = {
customerBranch?: (CustomerBranchCreate & {
id?: string;
branchCode?: string;
customerCode?: string;
})[];
selectedImage?: string;
code: string;
customerBranch?: (CustomerBranchCreate & { id?: string })[];
customerType: CustomerType;
status?: Status;
image: File | null;
customerType: CustomerType;
registeredBranchId: string;
namePrefix: string;
firstName: string;
lastName: string;
firstNameEN: string;
lastNameEN: string;
gender: string;
birthDate: Date;
image: File | null;
};
export type CustomerUpdate = {
selectedImage?: string;
status?: Status;
customerType?: CustomerType;
customerBranch?: (CustomerBranchCreate & { id?: string })[];
customerBranch?: (CustomerBranchCreate & {
id?: string;
branchCode?: string;
customerCode?: string;
})[];
image?: File;
registeredBranchId: string;