feat: agency personnel foreign address
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 5s

This commit is contained in:
puriphatt 2025-07-16 12:55:51 +07:00
parent 7f56a6219a
commit cdb38e301e
6 changed files with 323 additions and 36 deletions

View file

@ -12,7 +12,7 @@ import { formatAddress } from 'src/utils/address';
import useOptionStore from 'stores/options'; import useOptionStore from 'stores/options';
const optionStore = useOptionStore(); const optionStore = useOptionStore();
defineProps<{ const props = defineProps<{
title?: string; title?: string;
addressTitle?: string; addressTitle?: string;
addressTitleEN?: string; addressTitleEN?: string;
@ -30,6 +30,7 @@ defineProps<{
useEmployment?: boolean; useEmployment?: boolean;
useWorkPlace?: boolean; useWorkPlace?: boolean;
useForeignAddress?: boolean;
}>(); }>();
const addressStore = useAddressStore(); const addressStore = useAddressStore();
@ -57,6 +58,25 @@ const subDistrictId = defineModel<string | null | undefined>('subDistrictId');
const zipCode = defineModel<string | null | undefined>('zipCode'); const zipCode = defineModel<string | null | undefined>('zipCode');
const sameWithEmployer = defineModel<boolean>('sameWithEmployer'); const sameWithEmployer = defineModel<boolean>('sameWithEmployer');
const provinceTextEN = defineModel<string | null | undefined>(
'provinceTextEn',
{
default: '',
},
);
const districtTextEN = defineModel<string | null | undefined>(
'districtTextEn',
{
default: '',
},
);
const subDistrictTextEN = defineModel<string | null | undefined>(
'subDistrictTextEn',
{
default: '',
},
);
const homeCode = defineModel<string | null | undefined>('homeCode'); const homeCode = defineModel<string | null | undefined>('homeCode');
const employmentOffice = defineModel<string | null | undefined>( const employmentOffice = defineModel<string | null | undefined>(
'employmentOffice', 'employmentOffice',
@ -64,6 +84,7 @@ const employmentOffice = defineModel<string | null | undefined>(
const employmentOfficeEN = defineModel<string | null | undefined>( const employmentOfficeEN = defineModel<string | null | undefined>(
'employmentOfficeEn', 'employmentOfficeEn',
); );
const addressForeign = defineModel<boolean>('addressForeign');
const addrOptions = reactive<{ const addrOptions = reactive<{
provinceOps: Province[]; provinceOps: Province[];
@ -78,14 +99,18 @@ const addrOptions = reactive<{
const area = ref<Office[]>([]); const area = ref<Office[]>([]);
const fullAddress = computed(() => { const fullAddress = computed(() => {
const province = provinceOptions.value.find((v) => v.id === provinceId.value); const province = addressForeign.value
const district = districtOptions.value.find((v) => v.id === districtId.value); ? { id: '1', name: provinceId.value }
const sDistrict = subDistrictOptions.value.find( : provinceOptions.value.find((v) => v.id === provinceId.value);
(v) => v.id === subDistrictId.value, const district = addressForeign.value
); ? { id: '1', name: districtId.value }
: districtOptions.value.find((v) => v.id === districtId.value);
const sDistrict = addressForeign.value
? { id: '1', name: subDistrictId.value }
: subDistrictOptions.value.find((v) => v.id === subDistrictId.value);
if (province && district && sDistrict) { if (province?.name && district?.name && sDistrict?.name) {
const fullAddress = formatAddress({ const fullAddressText = formatAddress({
address: address.value, address: address.value,
addressEN: addressEN.value, addressEN: addressEN.value,
moo: moo.value ? moo.value : '', moo: moo.value ? moo.value : '',
@ -97,21 +122,26 @@ const fullAddress = computed(() => {
province: province as unknown as Province, province: province as unknown as Province,
district: district as unknown as District, district: district as unknown as District,
subDistrict: sDistrict as unknown as SubDistrict, subDistrict: sDistrict as unknown as SubDistrict,
zipCode: addressForeign.value ? zipCode.value || ' ' : undefined,
}); });
return fullAddress; return fullAddressText;
} }
return '-'; return '-';
}); });
const fullAddressEN = computed(() => { const fullAddressEN = computed(() => {
const province = provinceOptions.value.find((v) => v.id === provinceId.value); const province = addressForeign.value
const district = districtOptions.value.find((v) => v.id === districtId.value); ? { nameEN: provinceTextEN.value }
const sDistrict = subDistrictOptions.value.find( : provinceOptions.value.find((v) => v.id === provinceId.value);
(v) => v.id === subDistrictId.value, const district = addressForeign.value
); ? { nameEN: districtTextEN.value }
: districtOptions.value.find((v) => v.id === districtId.value);
const sDistrict = addressForeign.value
? { nameEN: subDistrictTextEN.value }
: subDistrictOptions.value.find((v) => v.id === subDistrictId.value);
if (province && district && sDistrict) { if (province?.nameEN && district?.nameEN && sDistrict?.nameEN) {
const fullAddress = formatAddress({ const fullAddressText = formatAddress({
address: address.value, address: address.value,
addressEN: addressEN.value, addressEN: addressEN.value,
moo: moo.value ? moo.value : '', moo: moo.value ? moo.value : '',
@ -124,8 +154,9 @@ const fullAddressEN = computed(() => {
district: district as unknown as District, district: district as unknown as District,
subDistrict: sDistrict as unknown as SubDistrict, subDistrict: sDistrict as unknown as SubDistrict,
en: true, en: true,
zipCode: addressForeign.value ? zipCode.value || ' ' : undefined,
}); });
return fullAddress; return fullAddressText;
} }
return '-'; return '-';
}); });
@ -149,7 +180,7 @@ async function fetchProvince() {
} }
async function fetchDistrict() { async function fetchDistrict() {
if (!provinceId.value) return; if (!provinceId.value || addressForeign.value) return;
const result = await addressStore.fetchDistrictByProvinceId(provinceId.value); const result = await addressStore.fetchDistrictByProvinceId(provinceId.value);
if (result) addrOptions.districtOps = result; if (result) addrOptions.districtOps = result;
@ -168,7 +199,7 @@ async function fetchDistrict() {
} }
async function fetchSubDistrict() { async function fetchSubDistrict() {
if (!districtId.value) return; if (!districtId.value || addressForeign.value) return;
const result = await addressStore.fetchSubDistrictByProvinceId( const result = await addressStore.fetchSubDistrictByProvinceId(
districtId.value, districtId.value,
); );
@ -255,6 +286,16 @@ onMounted(async () => {
await fetchSubDistrict(); await fetchSubDistrict();
}); });
function clearAddress() {
provinceId.value = null;
districtId.value = null;
subDistrictId.value = null;
provinceTextEN.value = null;
districtTextEN.value = null;
subDistrictTextEN.value = null;
zipCode.value = null;
}
watch(provinceId, fetchDistrict); watch(provinceId, fetchDistrict);
watch(districtId, fetchSubDistrict); watch(districtId, fetchSubDistrict);
@ -313,6 +354,15 @@ watchEffect(async () => {
{{ $t('customerEmployee.form.addressCustom') }} {{ $t('customerEmployee.form.addressCustom') }}
</span> </span>
</div> </div>
<div v-if="useForeignAddress" class="text-caption q-ml-md app-text-muted">
<q-checkbox
size="xs"
v-model="addressForeign"
@update:model-value="clearAddress"
/>
{{ $t('personnel.form.addressForeign') }}
</div>
</div> </div>
<div class="col-12 row q-col-gutter-y-md"> <div class="col-12 row q-col-gutter-y-md">
@ -449,7 +499,24 @@ watchEffect(async () => {
(v) => (typeof v === 'string' ? (street = v) : '') (v) => (typeof v === 'string' ? (street = v) : '')
" "
/> />
<q-input
v-if="addressForeign"
outlined
hide-bottom-space
class="col-md-3 col-6"
v-model="provinceId"
:dense="dense"
:label="$t('form.province')"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-province-${indexId}` : 'input-province'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-select <q-select
v-else
autocomplete="off" autocomplete="off"
outlined outlined
clearable clearable
@ -493,7 +560,24 @@ watchEffect(async () => {
</template> </template>
</q-select> </q-select>
<q-input
v-if="addressForeign"
outlined
hide-bottom-space
class="col-md-3 col-6"
v-model="districtId"
:dense="dense"
:label="$t('form.district')"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-district-${indexId}` : 'input-district'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-select <q-select
v-else
autocomplete="off" autocomplete="off"
outlined outlined
clearable clearable
@ -536,7 +620,25 @@ watchEffect(async () => {
</q-item> </q-item>
</template> </template>
</q-select> </q-select>
<q-input
v-if="addressForeign"
outlined
hide-bottom-space
class="col-md-3 col-6"
v-model="subDistrictId"
:dense="dense"
:label="$t('form.district')"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-sub-district-${indexId}` : 'input-sub-district'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-select <q-select
v-else
autocomplete="off" autocomplete="off"
outlined outlined
clearable clearable
@ -580,17 +682,26 @@ watchEffect(async () => {
</template> </template>
</q-select> </q-select>
<q-input <q-input
hide-bottom-space
:for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`" :for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
:dense="dense" :dense="dense"
outlined outlined
:disable="!readonly && !sameWithEmployer" :disable="!addressForeign && !readonly && !sameWithEmployer"
readonly :readonly="!addressForeign || readonly"
:label="$t('form.zipCode')" :label="$t('form.zipCode')"
class="col-md-3 col-6" class="col-md-3 col-6"
:model-value=" :model-value="
addrOptions.subDistrictOps !addressForeign
?.filter((x) => x.id === subDistrictId) ? (addrOptions.subDistrictOps
.map((x) => x.zipCode)[0] ?? '' ?.filter((x) => x.id === subDistrictId)
.map((x) => x.zipCode)[0] ?? '')
: zipCode
"
@update:model-value="(v) => (zipCode = v.toString())"
:rules="
!addressForeign
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
" "
/> />
<q-input <q-input
@ -689,7 +800,24 @@ watchEffect(async () => {
(v) => (typeof v === 'string' ? (streetEN = v) : '') (v) => (typeof v === 'string' ? (streetEN = v) : '')
" "
/> />
<q-input
v-if="addressForeign"
outlined
hide-bottom-space
class="col-md-3 col-6"
v-model="provinceTextEN"
:dense="dense"
label="Province"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-province-en-${indexId}` : 'input-province-en'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-select <q-select
v-else
autocomplete="off" autocomplete="off"
outlined outlined
clearable clearable
@ -732,7 +860,25 @@ watchEffect(async () => {
</q-item> </q-item>
</template> </template>
</q-select> </q-select>
<q-input
v-if="addressForeign"
outlined
hide-bottom-space
class="col-md-3 col-6"
v-model="districtTextEN"
:dense="dense"
label="District"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-district-en-${indexId}` : 'input-district-en'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-select <q-select
v-else
autocomplete="off" autocomplete="off"
outlined outlined
clearable clearable
@ -775,7 +921,25 @@ watchEffect(async () => {
</q-item> </q-item>
</template> </template>
</q-select> </q-select>
<q-input
v-if="addressForeign"
outlined
hide-bottom-space
class="col-md-3 col-6"
v-model="subDistrictTextEN"
:dense="dense"
label="Sub-District"
:readonly="readonly || sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-sub-district-en-${indexId}` : 'input-sub-district-en'}`"
:rules="
disabledRule
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
"
/>
<q-select <q-select
v-else
autocomplete="off" autocomplete="off"
outlined outlined
clearable clearable
@ -823,15 +987,23 @@ watchEffect(async () => {
:for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`" :for="`${prefixId}-${indexId !== undefined ? `input-zip-code-${indexId}` : 'input-zip-code'}`"
:dense="dense" :dense="dense"
outlined outlined
readonly :readonly="!addressForeign || readonly"
:disable="!readonly && !sameWithEmployer" :disable="!addressForeign && !readonly && !sameWithEmployer"
zip="zip-en" zip="zip-en"
label="Zip Code" label="Zip Code"
class="col-md-3 col-6" class="col-md-3 col-6"
:model-value=" :model-value="
addrOptions.subDistrictOps !addressForeign
?.filter((x) => x.id === subDistrictId) ? (addrOptions.subDistrictOps
.map((x) => x.zipCode)[0] ?? '' ?.filter((x) => x.id === subDistrictId)
.map((x) => x.zipCode)[0] ?? '')
: zipCode
"
@update:model-value="(v) => (zipCode = v.toString())"
:rules="
!addressForeign
? []
: [(val) => (val && val.length > 0) || $t('form.error.required')]
" "
/> />
<q-input <q-input

View file

@ -476,6 +476,7 @@ export default {
blacklist: 'Black list', blacklist: 'Black list',
contactName: 'Contact Person', contactName: 'Contact Person',
contactTel: 'Contact Number', contactTel: 'Contact Number',
addressForeign: 'Use foreign address',
}, },
}, },
customer: { customer: {

View file

@ -472,6 +472,7 @@ export default {
blacklist: 'แบล็คลิสต์', blacklist: 'แบล็คลิสต์',
contactName: 'ชื่อผู้ติดต่อ', contactName: 'ชื่อผู้ติดต่อ',
contactTel: 'เบอร์โทรศัพท์ผู้ติดต่อ', contactTel: 'เบอร์โทรศัพท์ผู้ติดต่อ',
addressForeign: 'ใช้ที่อยู่ต่างชาติ',
}, },
}, },
customer: { customer: {

View file

@ -157,6 +157,14 @@ const defaultFormData = {
contactTel: '', contactTel: '',
remark: '', remark: '',
agencyStatus: '', agencyStatus: '',
addressForeign: false,
provinceText: null,
districtText: null,
subDistrictText: null,
provinceTextEN: null,
districtTextEN: null,
subDistrictTextEN: null,
zipCodeText: null,
}; };
const formData = ref<UserCreate>({ const formData = ref<UserCreate>({
@ -209,6 +217,14 @@ const formData = ref<UserCreate>({
contactTel: '', contactTel: '',
remark: '', remark: '',
agencyStatus: '', agencyStatus: '',
addressForeign: false,
provinceText: null,
districtText: null,
subDistrictText: null,
provinceTextEN: null,
districtTextEN: null,
subDistrictTextEN: null,
zipCodeText: null,
}); });
const fieldSelectedOption = ref<{ label: string; value: string }[]>([ const fieldSelectedOption = ref<{ label: string; value: string }[]>([
@ -431,6 +447,28 @@ async function onSubmit(excludeDialog?: boolean) {
...formData.value, ...formData.value,
checkpointEN: formData.value.checkpoint, checkpointEN: formData.value.checkpoint,
status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE', status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE',
provinceId: formData.value.addressForeign
? null
: formData.value.provinceId,
districtId: formData.value.addressForeign
? null
: formData.value.districtId,
subDistrictId: formData.value.addressForeign
? null
: formData.value.subDistrictId,
provinceText: formData.value.addressForeign
? formData.value.provinceId
: null,
districtText: formData.value.addressForeign
? formData.value.districtId
: null,
subDistrictText: formData.value.addressForeign
? formData.value.subDistrictId
: null,
zipCodeText: formData.value.addressForeign
? formData.value.zipCode
: null,
} as const; } as const;
await userStore.editById(currentUser.value.id, formDataEdit); await userStore.editById(currentUser.value.id, formDataEdit);
@ -462,7 +500,31 @@ async function onSubmit(excludeDialog?: boolean) {
: ''; : '';
formData.value.checkpointEN = formData.value.checkpoint; formData.value.checkpointEN = formData.value.checkpoint;
const result = await userStore.create( const result = await userStore.create(
formData.value, {
...formData.value,
provinceId: formData.value.addressForeign
? null
: formData.value.provinceId,
districtId: formData.value.addressForeign
? null
: formData.value.districtId,
subDistrictId: formData.value.addressForeign
? null
: formData.value.subDistrictId,
provinceText: formData.value.addressForeign
? formData.value.provinceId
: null,
districtText: formData.value.addressForeign
? formData.value.districtId
: null,
subDistrictText: formData.value.addressForeign
? formData.value.subDistrictId
: null,
zipCodeText: formData.value.addressForeign
? formData.value.zipCode
: null,
},
onCreateImageList.value, onCreateImageList.value,
); );
@ -560,12 +622,20 @@ async function assignFormData(idEdit: string) {
currentUser.value = foundUser; currentUser.value = foundUser;
formData.value = { formData.value = {
branchId: foundUser.branch[0]?.id, branchId: foundUser.branch[0]?.id,
provinceId: foundUser.provinceId, provinceId: foundUser.addressForeign
districtId: foundUser.districtId, ? foundUser.provinceText
subDistrictId: foundUser.subDistrictId, : foundUser.provinceId,
districtId: foundUser.addressForeign
? foundUser.districtText
: foundUser.districtId,
subDistrictId: foundUser.addressForeign
? foundUser.subDistrictText
: foundUser.subDistrictId,
telephoneNo: foundUser.telephoneNo, telephoneNo: foundUser.telephoneNo,
email: foundUser.email, email: foundUser.email,
zipCode: foundUser.zipCode, zipCode: foundUser.addressForeign
? foundUser.zipCodeText
: foundUser.zipCode,
gender: foundUser.gender, gender: foundUser.gender,
addressEN: foundUser.addressEN, addressEN: foundUser.addressEN,
address: foundUser.address, address: foundUser.address,
@ -619,6 +689,10 @@ async function assignFormData(idEdit: string) {
(foundUser.citizenExpire && new Date(foundUser.citizenExpire)) || null, (foundUser.citizenExpire && new Date(foundUser.citizenExpire)) || null,
remark: foundUser.remark || '', remark: foundUser.remark || '',
agencyStatus: foundUser.agencyStatus || '', agencyStatus: foundUser.agencyStatus || '',
addressForeign: foundUser.addressForeign || false,
provinceTextEN: foundUser.provinceTextEN,
districtTextEN: foundUser.districtTextEN,
subDistrictTextEN: foundUser.subDistrictTextEN,
}; };
formData.value.status === 'ACTIVE' || 'CREATED' formData.value.status === 'ACTIVE' || 'CREATED'
@ -745,7 +819,17 @@ watch(
watch( watch(
() => formData.value.userType, () => formData.value.userType,
async () => { async (type) => {
if (type !== 'AGENCY') {
formData.value.addressForeign = false;
formData.value.provinceId = null;
formData.value.districtId = null;
formData.value.subDistrictId = null;
formData.value.provinceTextEN = null;
formData.value.districtTextEN = null;
formData.value.subDistrictTextEN = null;
formData.value.zipCodeText = null;
}
if (!infoDrawerEdit.value) return; if (!infoDrawerEdit.value) return;
formData.value.registrationNo = null; formData.value.registrationNo = null;
formData.value.startDate = null; formData.value.startDate = null;
@ -1813,10 +1897,15 @@ watch(
v-model:district-id="formData.districtId" v-model:district-id="formData.districtId"
v-model:sub-district-id="formData.subDistrictId" v-model:sub-district-id="formData.subDistrictId"
v-model:zip-code="formData.zipCode" v-model:zip-code="formData.zipCode"
v-model:address-foreign="formData.addressForeign"
v-model:province-text-en="formData.provinceTextEN"
v-model:district-text-en="formData.districtTextEN"
v-model:sub-district-text-en="formData.subDistrictTextEN"
:readonly="!infoDrawerEdit" :readonly="!infoDrawerEdit"
prefix-id="drawer-info-personnel" prefix-id="drawer-info-personnel"
:title="'personnel.form.addressInformation'" :title="'personnel.form.addressInformation'"
dense dense
:use-foreign-address="formData.userType === 'AGENCY'"
class="q-mb-xl" class="q-mb-xl"
/> />
<FormByType <FormByType
@ -2042,8 +2131,13 @@ watch(
v-model:district-id="formData.districtId" v-model:district-id="formData.districtId"
v-model:sub-district-id="formData.subDistrictId" v-model:sub-district-id="formData.subDistrictId"
v-model:zip-code="formData.zipCode" v-model:zip-code="formData.zipCode"
v-model:address-foreign="formData.addressForeign"
v-model:province-text-en="formData.provinceTextEN"
v-model:district-text-en="formData.districtTextEN"
v-model:sub-district-text-en="formData.subDistrictTextEN"
prefix-id="drawer-info-personnel" prefix-id="drawer-info-personnel"
dense dense
:use-foreign-address="formData.userType === 'AGENCY'"
class="q-mb-xl" class="q-mb-xl"
/> />
<FormByType <FormByType

View file

@ -61,6 +61,14 @@ export type User = {
contactTel?: string; contactTel?: string;
remark?: string; remark?: string;
agencyStatus?: AgencyStatus; agencyStatus?: AgencyStatus;
addressForeign?: boolean;
provinceText?: string | null;
districtText?: string | null;
subDistrictText?: string | null;
provinceTextEN?: string | null;
districtTextEN?: string | null;
subDistrictTextEN?: string | null;
zipCodeText?: string | null;
}; };
export type UserCreate = { export type UserCreate = {
@ -113,6 +121,14 @@ export type UserCreate = {
contactTel?: string; contactTel?: string;
remark?: string; remark?: string;
agencyStatus?: AgencyStatus | string; agencyStatus?: AgencyStatus | string;
addressForeign?: boolean;
provinceText?: string | null;
districtText?: string | null;
subDistrictText?: string | null;
provinceTextEN?: string | null;
districtTextEN?: string | null;
subDistrictTextEN?: string | null;
zipCodeText?: string | null;
}; };
export enum AgencyStatus { export enum AgencyStatus {

View file

@ -14,6 +14,7 @@ export function formatAddress(opt: {
district?: District | null; district?: District | null;
subDistrict?: SubDistrict | null; subDistrict?: SubDistrict | null;
en?: boolean; en?: boolean;
zipCode?: string;
}) { }) {
const { t } = useI18n(); const { t } = useI18n();
let addressParts: string[]; let addressParts: string[];
@ -58,7 +59,9 @@ export function formatAddress(opt: {
// ); // );
} }
if (opt.subDistrict) addressParts.push(`${opt.subDistrict.zipCode}`); if (opt.subDistrict && !opt.zipCode)
addressParts.push(`${opt.subDistrict.zipCode}`);
if (opt.zipCode) addressParts.push(`${opt.zipCode}`);
return addressParts.join(' '); return addressParts.join(' ');
} }