feat(02): citizen id, issue, expire

This commit is contained in:
puriphatt 2024-09-12 15:41:54 +07:00
parent 6a6bf68cd9
commit aece743ccf
6 changed files with 387 additions and 264 deletions

View file

@ -20,6 +20,9 @@ const birthDate = defineModel<Date | string | null>('birthDate');
const nationality = defineModel<string>('nationality');
const midName = defineModel<string | null>('midName');
const midNameEN = defineModel<string | null>('midNameEN');
const citizenId = defineModel<string>('citizenId');
const citizenIssue = defineModel<Date | null>('citizenIssue');
const citizenExpire = defineModel<Date | null>('citizenExpire');
const props = defineProps<{
dense?: boolean;
@ -112,6 +115,26 @@ watch(
</div>
<div class="col-12 row q-col-gutter-sm">
<q-input
v-if="!employee"
outlined
class="col-5"
hide-bottom-space
v-model="citizenId"
mask="#############"
:readonly="readonly"
:dense="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"
/>
<div class="col-12 row" style="display: flex; gap: var(--size-2)">
<q-select
outlined
@ -196,7 +219,7 @@ watch(
:readonly="readonly"
:disable="!readonly"
class="col-md-1 col-6"
:label="$t('personnel.form.prefixName')"
label="Title"
:model-value="
readonly
? capitalize(prefixName || '') || '-'
@ -215,7 +238,7 @@ watch(
:readonly="readonly"
hide-bottom-space
class="col"
:label="$t('personnel.form.firstNameEN')"
label="Name"
v-model="firstNameEN"
:rules="[
(val: string) => !!val || $t('form.error.required'),
@ -230,7 +253,7 @@ watch(
:readonly="readonly"
hide-bottom-space
class="col-md-3 col-6"
:label="$t('personnel.form.middleNameEN')"
label="Mid Name"
:model-value="readonly ? midNameEN || '-' : midNameEN"
@update:model-value="
(v) => (typeof v === 'string' ? (midNameEN = v) : '')
@ -244,7 +267,7 @@ watch(
:readonly="readonly"
hide-bottom-space
class="col"
:label="$t('personnel.form.lastNameEN')"
label="Surname"
v-model="lastNameEN"
:rules="[
(val: string) => !!val || $t('form.error.required'),
@ -268,12 +291,22 @@ watch(
(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-input
v-if="!employee"
:for="`${prefixId}-input-email`"
:dense="dense"
outlined
hide-bottom-space
:readonly="readonly"
:label="$t('form.email')"
:rules="
@ -290,7 +323,16 @@ watch(
:model-value="readonly ? email || '-' : email"
@update:model-value="(v) => (typeof v === 'string' ? (email = v) : '')"
@clear="email = ''"
/>
>
<template #prepend>
<q-icon
size="xs"
name="mdi-email-outline"
class="cursor-pointer"
color="primary"
/>
</template>
</q-input>
<q-select
v-if="!employee"
@ -355,6 +397,33 @@ watch(
"
/>
<DatePicker
v-if="!employee"
v-model="citizenIssue"
class="col-md-2 col-6"
:id="`${prefixId}-input-citizen-issue`"
:readonly="readonly"
:label="$t('personnel.form.citizenIssue')"
:disabled-dates="disabledAfterToday"
:rules="[
(val: string) =>
!!val ||
$t('form.error.selectField', {
field: $t('personnel.form.citizenIssue'),
}),
]"
/>
<DatePicker
v-if="!employee"
v-model="citizenExpire"
class="col-md-2 col-6"
:id="`${prefixId}-input-citizen-expire`"
:readonly="readonly"
:label="$t('personnel.form.citizenExpire')"
:disabled-dates="disabledAfterToday"
/>
<q-select
v-if="employee"
outlined

View file

@ -498,7 +498,7 @@ watch(districtId, fetchSubDistrict);
:label="$t('form.fullAddress')"
readonly
:disable="!readonly && !sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-street-${indexId}` : 'input-street'}`"
:for="`${prefixId}-${indexId !== undefined ? `input-full-address-${indexId}` : 'input-full-address'}`"
/>
</div>
@ -727,7 +727,7 @@ watch(districtId, fetchSubDistrict);
label="Full Address"
readonly
:disable="!readonly && !sameWithEmployer"
:for="`${prefixId}-${indexId !== undefined ? `input-street-${indexId}` : 'input-street'}`"
:for="`${prefixId}-${indexId !== undefined ? `input-full-address-en-${indexId}` : 'input-full-address-en'}`"
/>
</div>
</div>

View file

@ -270,6 +270,9 @@ export default {
checkpoint: 'Checkpoint',
checkpointEN: 'Checkpoint (EN)',
attachment: 'Attachment Document',
citizenId: 'Citizen ID',
citizenIssue: 'Citizen Issue',
citizenExpire: 'Citizen Expire',
},
},
customer: {

View file

@ -269,6 +269,9 @@ export default {
checkpoint: 'ด่าน',
checkpointEN: 'ด่าน ภาษาอังกฤษ',
attachment: 'เอกสารประจำตัว',
citizenId: 'เลขที่บัตรประชาชน',
citizenIssue: 'วันที่ออกบัตร',
citizenExpire: 'วันที่หมดอายุ',
},
},
customer: {

View file

@ -1,14 +1,19 @@
<script setup lang="ts">
import { ref, onMounted, watch, computed } from 'vue';
import useUtilsStore, { dialog, baseUrl } from 'stores/utils';
import { calculateAge } from 'src/utils/datetime';
import { useQuasar, type QTableProps } from 'quasar';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import useFlowStore from 'stores/flow';
import useUserStore from 'stores/user';
import useFlowStore from 'stores/flow';
import useBranchStore from 'stores/branch';
import useOptionStore from 'stores/options';
import useAddressStore from 'stores/address';
import useMyBranch from 'src/stores/my-branch';
import { calculateAge } from 'src/utils/datetime';
import { useQuasar, type QTableProps } from 'quasar';
import useUtilsStore, { dialog, baseUrl } from 'stores/utils';
import { isRoleInclude, resetScrollBar } from 'src/stores/utils';
import { BranchUserStats } from 'stores/branch/types';
import {
User,
@ -24,42 +29,99 @@ import {
UndoButton,
} from 'components/button';
import { BranchUserStats } from 'stores/branch/types';
import useAddressStore from 'stores/address';
import ButtonAddComponent from 'components/ButtonAddCompoent.vue';
import PersonCard from 'components/shared/PersonCard.vue';
import StatCardComponent from 'components/StatCardComponent.vue';
import NoData from 'components/NoData.vue';
import { AddressForm } from 'components/form';
import SideMenu from 'components/SideMenu.vue';
import AddButton from 'components/AddButton.vue';
import DialogForm from 'components/DialogForm.vue';
import DrawerInfo from 'components/DrawerInfo.vue';
import ProfileBanner from 'components/ProfileBanner.vue';
import PersonCard from 'components/shared/PersonCard.vue';
import KebabAction from 'components/shared/KebabAction.vue';
import TooltipComponent from 'components/TooltipComponent.vue';
import FormInformation from 'components/02_personnel-management/FormInformation.vue';
import StatCardComponent from 'components/StatCardComponent.vue';
import ImageUploadDialog from 'components/ImageUploadDialog.vue';
import ButtonAddComponent from 'components/ButtonAddCompoent.vue';
import PaginationComponent from 'components/PaginationComponent.vue';
import InfoForm from 'components/02_personnel-management/InfoForm.vue';
import FormPerson from 'components/02_personnel-management/FormPerson.vue';
import FormByType from 'components/02_personnel-management/FormByType.vue';
import DrawerInfo from 'components/DrawerInfo.vue';
import InfoForm from 'components/02_personnel-management/InfoForm.vue';
import NoData from 'components/NoData.vue';
import PaginationComponent from 'components/PaginationComponent.vue';
import useOptionStore from 'stores/options';
import ProfileBanner from 'components/ProfileBanner.vue';
import SideMenu from 'components/SideMenu.vue';
import ImageUploadDialog from 'components/ImageUploadDialog.vue';
import { AddressForm } from 'components/form';
import DialogForm from 'components/DialogForm.vue';
import KebabAction from 'src/components/shared/KebabAction.vue';
import useMyBranch from 'src/stores/my-branch';
import FormInformation from 'components/02_personnel-management/FormInformation.vue';
const { locale, t } = useI18n();
const $q = useQuasar();
const optionStore = useOptionStore();
const utilsStore = useUtilsStore();
const flowStore = useFlowStore();
const userStore = useUserStore();
const flowStore = useFlowStore();
const utilsStore = useUtilsStore();
const optionStore = useOptionStore();
const branchStore = useBranchStore();
const adrressStore = useAddressStore();
const useMyBranchStore = useMyBranch();
const { data: userData } = storeToRefs(userStore);
const { myBranch } = storeToRefs(useMyBranchStore);
// state & control
const modal = ref(false);
const isEdit = ref(false);
const hideStat = ref(false);
const modeView = ref(false);
const infoDrawer = ref(false);
const isImageEdit = ref(false);
const imageDialog = ref(false);
const infoDrawerEdit = ref(false);
const refreshImageState = ref(false);
const inputSearch = ref('');
const currentTab = ref<string>('ALL');
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
const currentPage = ref(1);
const pageSize = ref(30);
const currentMaxPage = computed(() =>
userData.value ? Math.ceil(userData.value?.total / pageSize.value) : 1,
);
// form & data
const hqId = ref<string>();
const brId = ref<string>();
const currentUser = ref<User>();
const userCode = ref<string>();
const statusToggle = ref(true);
const agencyFile = ref<File[]>([]);
const agencyFileList = ref<{ name: string; url: string }[]>([]);
const typeStats = ref<UserTypeStats>();
const userStats = ref<BranchUserStats[]>();
const urlProfile = ref<string>();
const profileFileImg = ref<File | null>(null);
const imageList = ref<{ selectedImage: string; list: string[] }>();
const onCreateImageList = ref<{
selectedImage: string;
list: { url: string; imgFile: File | null; name: string }[];
}>({ selectedImage: '', list: [] });
const formMenuIcon = ref<{ icon: string; color: string; bgColor: string }[]>([
{
icon: 'mdi-account-outline',
color: 'hsl(var(--info-bg))',
bgColor: 'var(--surface-1)',
},
{
icon: 'mdi-map-marker-radius-outline',
color: 'hsl(var(--info-bg))',
bgColor: 'var(--surface-1)',
},
{
icon: 'mdi-briefcase-outline',
color: 'hsl(var(--info-bg))',
bgColor: 'var(--surface-1)',
},
]);
const defaultFormData = {
provinceId: null,
districtId: null,
@ -70,6 +132,12 @@ const defaultFormData = {
gender: '',
addressEN: '',
address: '',
mooEN: '',
moo: '',
soiEN: '',
soi: '',
streetEN: '',
street: '',
trainingPlace: null,
importNationality: null,
sourceNationality: null,
@ -95,9 +163,58 @@ const defaultFormData = {
namePrefix: null,
middleNameEN: '',
middleName: '',
citizenExpire: null,
citizenIssue: null,
citizenId: '',
};
const modeView = ref(false);
const formData = ref<UserCreate>({
selectedImage: '',
branchId: '',
provinceId: null,
districtId: null,
subDistrictId: null,
telephoneNo: '',
email: '',
zipCode: '',
gender: '',
addressEN: '',
address: '',
mooEN: '',
moo: '',
soiEN: '',
soi: '',
streetEN: '',
street: '',
trainingPlace: null,
importNationality: null,
sourceNationality: null,
licenseExpireDate: null,
licenseIssueDate: null,
licenseNo: null,
discountCondition: null,
retireDate: null,
startDate: null,
registrationNo: null,
lastNameEN: '',
lastName: '',
middleNameEN: '',
middleName: '',
firstNameEN: '',
firstName: '',
namePrefix: null,
userRole: '',
userType: '',
birthDate: null,
responsibleArea: null,
checkpoint: null,
checkpointEN: null,
username: '',
status: 'CREATED',
citizenExpire: null,
citizenIssue: null,
citizenId: '',
});
const fieldSelectedOption = ref<{ label: string; value: string }[]>([
{
@ -131,25 +248,6 @@ const fieldSelectedOption = ref<{ label: string; value: string }[]>([
},
]);
const formMenuIcon = ref<{ icon: string; color: string; bgColor: string }[]>([
{
icon: 'mdi-account-outline',
color: 'hsl(var(--info-bg))',
bgColor: 'var(--surface-1)',
},
{
icon: 'mdi-map-marker-radius-outline',
color: 'hsl(var(--info-bg))',
bgColor: 'var(--surface-1)',
},
{
icon: 'mdi-briefcase-outline',
color: 'hsl(var(--info-bg))',
bgColor: 'var(--surface-1)',
},
]);
const fieldSelected = ref<
(
| 'orderNumber'
@ -170,86 +268,6 @@ const fieldSelected = ref<
'userRole',
]);
const refImageUpload = ref<InstanceType<typeof ImageUploadDialog>>();
const hideStat = ref(false);
const userCode = ref<string>();
const currentUser = ref<User>();
const infoDrawerEdit = ref(false);
const infoPersonId = ref<string>('');
const infoDrawer = ref(false);
const profileSubmit = ref(false);
const urlProfile = ref<string>();
const isEdit = ref(false);
const modal = ref(false);
const statusToggle = ref(true);
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
const inputSearch = ref('');
const userId = ref<string>();
const selectorLabel = ref<string>('ALL');
const hqId = ref<string>();
const brId = ref<string>();
const formDialogRef = ref();
const userStats = ref<BranchUserStats[]>();
const typeStats = ref<UserTypeStats>();
const agencyFile = ref<File[]>([]);
const agencyFileList = ref<{ name: string; url: string }[]>([]);
const formData = ref<UserCreate>({
selectedImage: '',
branchId: '',
provinceId: null,
districtId: null,
subDistrictId: null,
telephoneNo: '',
email: '',
zipCode: '',
gender: '',
addressEN: '',
address: '',
trainingPlace: null,
importNationality: null,
sourceNationality: null,
licenseExpireDate: null,
licenseIssueDate: null,
licenseNo: null,
discountCondition: null,
retireDate: null,
startDate: null,
registrationNo: null,
lastNameEN: '',
lastName: '',
middleNameEN: '',
middleName: '',
firstNameEN: '',
firstName: '',
namePrefix: null,
userRole: '',
userType: '',
birthDate: null,
responsibleArea: null,
checkpoint: null,
checkpointEN: null,
username: '',
status: 'CREATED',
});
const isImageEdit = ref<boolean>(false);
const imageUrl = ref<string>('');
const profileFileImg = ref<File | null>(null);
const imageDialog = ref(false);
const refreshImageState = ref(false);
const imageList = ref<{ selectedImage: string; list: string[] }>();
const onCreateImageList = ref<{
selectedImage: string;
list: { url: string; imgFile: File | null; name: string }[];
}>({ selectedImage: '', list: [] });
// const inputFile = document.createElement('input');
// inputFile.type = 'file';
// inputFile.accept = 'image/*';
// const reader = new FileReader();
const columns = [
{
name: 'orderNumber',
@ -297,9 +315,53 @@ const columns = [
},
] satisfies QTableProps['columns'];
// watch(profileFileImg, () => {
// if (profileFileImg.value) reader.readAsDataURL(profileFileImg.value);
// });
function undo() {
if (!currentUser.value) return;
isImageEdit.value = false;
infoDrawerEdit.value = false;
assignFormData(currentUser.value.id);
}
function mapRole(value: string) {
const option = userStore.userOption.roleOpts.find(
(option) => option.value === value,
);
return option ? option.label : '-';
}
function mapUserType(label: string) {
const userTypeMap: { [key: string]: string } = {
USER: 'USER',
MESSENGER: 'MESSENGER',
DELEGATE: 'DELEGATE',
AGENCY: 'AGENCY',
};
formData.value.userType = userTypeMap[label];
}
function onClose(excludeDialog?: boolean) {
if (excludeDialog) {
infoDrawer.value = excludeDialog || false;
return;
}
hqId.value = '';
brId.value = '';
userCode.value = '';
urlProfile.value = '';
profileFileImg.value = null;
infoDrawerEdit.value = false;
agencyFile.value = [];
modal.value = false;
isEdit.value = false;
statusToggle.value = true;
isImageEdit.value = false;
currentUser.value = undefined;
Object.assign(formData.value, defaultFormData);
mapUserType(currentTab.value);
imageList.value = { selectedImage: '', list: [] };
onCreateImageList.value = { selectedImage: '', list: [] };
flowStore.rotate();
}
async function openDialog(
action?: 'FORM' | 'INFO',
@ -366,41 +428,9 @@ async function openDialog(
userStore.userOption.brOpts = [];
}
function undo() {
if (!infoPersonId.value) return;
isImageEdit.value = false;
infoDrawerEdit.value = false;
assignFormData(infoPersonId.value);
}
function onClose(excludeDialog?: boolean) {
if (excludeDialog) {
infoDrawer.value = excludeDialog || false;
return;
}
hqId.value = '';
brId.value = '';
userId.value = '';
userCode.value = '';
urlProfile.value = '';
profileFileImg.value = null;
infoDrawerEdit.value = false;
agencyFile.value = [];
modal.value = false;
isEdit.value = false;
profileSubmit.value = false;
statusToggle.value = true;
isImageEdit.value = false;
currentUser.value = undefined;
Object.assign(formData.value, defaultFormData);
mapUserType(selectorLabel.value);
imageList.value = { selectedImage: '', list: [] };
onCreateImageList.value = { selectedImage: '', list: [] };
flowStore.rotate();
}
async function onSubmit(excludeDialog?: boolean) {
if (isEdit.value && userId.value) {
if (!userId.value) return;
if (isEdit.value && currentUser.value) {
if (!currentUser.value.id) return;
formData.value.branchId = brId.value
? brId.value
@ -412,16 +442,16 @@ async function onSubmit(excludeDialog?: boolean) {
status: !statusToggle.value ? 'INACTIVE' : 'ACTIVE',
} as const;
await userStore.editById(userId.value, formDataEdit);
await userStore.editById(currentUser.value.id, formDataEdit);
if (userId.value && formDataEdit.userType === 'AGENCY') {
if (currentUser.value.id && formDataEdit.userType === 'AGENCY') {
if (!agencyFile.value) return;
const payload: UserAttachmentCreate = {
file: agencyFile.value,
};
if (payload?.file) {
await userStore.addAttachment(userId.value, payload);
await userStore.addAttachment(currentUser.value.id, payload);
}
}
@ -463,7 +493,7 @@ async function onSubmit(excludeDialog?: boolean) {
}
}
selectorLabel.value = formData.value.userType;
currentTab.value = formData.value.userType;
await fetchUserList();
@ -496,16 +526,6 @@ async function onDelete(id: string) {
});
}
function mapUserType(label: string) {
const userTypeMap: { [key: string]: string } = {
USER: 'USER',
MESSENGER: 'MESSENGER',
DELEGATE: 'DELEGATE',
AGENCY: 'AGENCY',
};
formData.value.userType = userTypeMap[label];
}
async function toggleStatus(id: string) {
const record = userData.value?.result.find((v) => v.id === id);
@ -549,9 +569,6 @@ async function assignFormData(idEdit: string) {
if (foundUser) {
currentUser.value = foundUser;
if (currentUser.value) {
infoPersonId.value = currentUser.value.id;
}
formData.value = {
branchId: foundUser.branch[0]?.id,
provinceId: foundUser.provinceId,
@ -563,6 +580,12 @@ async function assignFormData(idEdit: string) {
gender: foundUser.gender,
addressEN: foundUser.addressEN,
address: foundUser.address,
moo: foundUser.moo,
mooEN: foundUser.mooEN,
soi: foundUser.soi,
soiEN: foundUser.soiEN,
street: foundUser.street,
streetEN: foundUser.streetEN,
trainingPlace: foundUser.trainingPlace,
importNationality: foundUser.importNationality,
sourceNationality: foundUser.sourceNationality,
@ -595,12 +618,16 @@ async function assignFormData(idEdit: string) {
(foundUser.retireDate && new Date(foundUser.retireDate)) || null,
startDate: (foundUser.startDate && new Date(foundUser.startDate)) || null,
birthDate: (foundUser.birthDate && new Date(foundUser.birthDate)) || null,
citizenId: foundUser.citizenId,
citizenIssue:
(foundUser.citizenIssue && new Date(foundUser.citizenIssue)) || null,
citizenExpire:
(foundUser.citizenExpire && new Date(foundUser.citizenExpire)) || null,
};
formData.value.status === 'ACTIVE' || 'CREATED'
? (statusToggle.value = true)
: (statusToggle.value = false);
userId.value = foundUser.id;
if (foundUser.branch) {
if (foundUser.branch?.[0].isHeadOffice) {
@ -615,7 +642,6 @@ async function assignFormData(idEdit: string) {
urlProfile.value = `${baseUrl}/user/${foundUser.id}/profile-image/${foundUser.selectedImage}`;
isEdit.value = true;
profileSubmit.value = true;
hqId.value && (await userStore.fetchBrOption(hqId.value));
await fetchImageList(foundUser.id, foundUser.selectedImage);
@ -628,6 +654,31 @@ async function assignFormData(idEdit: string) {
}
}
async function fetchImageList(id: string, selectedName: string) {
const res = await userStore.fetchImageListById(id);
imageList.value = {
selectedImage: selectedName,
list: res.map((n: string) => `user/${id}/profile-image/${n}`),
};
return res;
}
async function fetchUserList() {
await userStore.fetchList({
includeBranch: true,
pageSize: pageSize.value,
page: currentPage.value,
query: !!inputSearch.value ? inputSearch.value : undefined,
userType: currentTab.value === 'ALL' ? undefined : currentTab.value,
status:
statusFilter.value === 'all'
? undefined
: statusFilter.value === 'statusACTIVE'
? 'ACTIVE'
: 'INACTIVE',
});
}
onMounted(async () => {
utilsStore.currentTitle.title = 'personnel.title';
utilsStore.currentTitle.path = [{ text: 'personnel.caption', i18n: true }];
@ -649,24 +700,8 @@ onMounted(async () => {
flowStore.rotate();
});
function mapRole(value: string) {
const option = userStore.userOption.roleOpts.find(
(option) => option.value === value,
);
return option ? option.label : '-';
}
async function fetchImageList(id: string, selectedName: string) {
const res = await userStore.fetchImageListById(id);
imageList.value = {
selectedImage: selectedName,
list: res.map((n: string) => `user/${id}/profile-image/${n}`),
};
return res;
}
watch(
() => selectorLabel.value,
() => currentTab.value,
async (label) => {
mapUserType(label);
await fetchUserList();
@ -695,28 +730,6 @@ watch(
},
);
const currentPage = ref(1);
const pageSize = ref(30);
const currentMaxPage = computed(() =>
userData.value ? Math.ceil(userData.value?.total / pageSize.value) : 1,
);
async function fetchUserList() {
await userStore.fetchList({
includeBranch: true,
pageSize: pageSize.value,
page: currentPage.value,
query: !!inputSearch.value ? inputSearch.value : undefined,
userType: selectorLabel.value === 'ALL' ? undefined : selectorLabel.value,
status:
statusFilter.value === 'all'
? undefined
: statusFilter.value === 'statusACTIVE'
? 'ACTIVE'
: 'INACTIVE',
});
}
watch(
() => profileFileImg.value,
() => {
@ -762,9 +775,9 @@ watch(
"
>
{{
selectorLabel === 'ALL'
currentTab === 'ALL'
? Object.values(typeStats).reduce((acc, val) => acc + val, 0)
: typeStats[selectorLabel]
: typeStats[currentTab]
}}
</q-badge>
<q-btn
@ -788,7 +801,7 @@ watch(
v-if="typeStats && userData?.result"
labelI18n
:branch="
selectorLabel === 'ALL'
currentTab === 'ALL'
? Object.entries(typeStats).map(([key, val]) => ({
count: val,
label: `personnel.${key}`,
@ -805,15 +818,15 @@ watch(
}))
: [
{
label: `personnel.${selectorLabel}`,
count: typeStats[selectorLabel],
label: `personnel.${currentTab}`,
count: typeStats[currentTab],
icon: 'mdi-account-outline',
color:
selectorLabel === 'USER'
currentTab === 'USER'
? 'cyan'
: selectorLabel === 'MESSENGER'
: currentTab === 'MESSENGER'
? 'yellow'
: selectorLabel === 'DELEGATE'
: currentTab === 'DELEGATE'
? 'red'
: 'magenta',
},
@ -952,7 +965,7 @@ watch(
inline-label
mobile-arrows
dense
v-model="selectorLabel"
v-model="currentTab"
align="left"
class="full-width"
active-color="info"
@ -963,7 +976,7 @@ watch(
async () => {
currentPage = 1;
inputSearch = '';
selectorLabel = 'ALL';
currentTab = 'ALL';
statusFilter = 'all';
flowStore.rotate();
}
@ -971,9 +984,7 @@ watch(
>
<div
class="row text-capitalize"
:class="
selectorLabel === 'ALL' ? 'text-bold' : 'app-text-muted'
"
:class="currentTab === 'ALL' ? 'text-bold' : 'app-text-muted'"
>
{{ $t('general.all') }}
</div>
@ -982,7 +993,7 @@ watch(
name="USER"
@click="
async () => {
selectorLabel = 'USER';
currentTab = 'USER';
statusFilter = 'all';
currentPage = 1;
inputSearch = '';
@ -992,9 +1003,7 @@ watch(
>
<div
class="row text-capitalize"
:class="
selectorLabel === 'USER' ? 'text-bold' : 'app-text-muted'
"
:class="currentTab === 'USER' ? 'text-bold' : 'app-text-muted'"
>
{{ $t('personnel.USER') }}
</div>
@ -1003,7 +1012,7 @@ watch(
name="MESSENGER"
@click="
async () => {
selectorLabel = 'MESSENGER';
currentTab = 'MESSENGER';
statusFilter = 'all';
currentPage = 1;
inputSearch = '';
@ -1014,7 +1023,7 @@ watch(
<div
class="row text-capitalize"
:class="
selectorLabel === 'MESSENGER' ? 'text-bold' : 'app-text-muted'
currentTab === 'MESSENGER' ? 'text-bold' : 'app-text-muted'
"
>
{{ $t('personnel.MESSENGER') }}
@ -1024,7 +1033,7 @@ watch(
name="DELEGATE"
@click="
async () => {
selectorLabel = 'DELEGATE';
currentTab = 'DELEGATE';
statusFilter = 'all';
currentPage = 1;
inputSearch = '';
@ -1035,7 +1044,7 @@ watch(
<div
class="row text-capitalize"
:class="
selectorLabel === 'DELEGATE' ? 'text-bold' : 'app-text-muted'
currentTab === 'DELEGATE' ? 'text-bold' : 'app-text-muted'
"
>
{{ $t('personnel.DELEGATE') }}
@ -1045,7 +1054,7 @@ watch(
name="AGENCY"
@click="
async () => {
selectorLabel = 'AGENCY';
currentTab = 'AGENCY';
statusFilter = 'all';
currentPage = 1;
inputSearch = '';
@ -1056,7 +1065,7 @@ watch(
<div
class="row text-capitalize"
:class="
selectorLabel === 'AGENCY' ? 'text-bold' : 'app-text-muted'
currentTab === 'AGENCY' ? 'text-bold' : 'app-text-muted'
"
>
{{ $t('personnel.AGENCY') }}
@ -1186,7 +1195,7 @@ watch(
<div class="column">
<div class="col ellipsis" style="max-width: 20vw">
{{
$i18n.locale === 'eng'
locale === 'eng'
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
: `${props.row.firstName} ${props.row.lastName}`.trim()
}}
@ -1196,7 +1205,7 @@ watch(
:delay="300"
>
{{
$i18n.locale === 'eng'
locale === 'eng'
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
: `${props.row.firstName} ${props.row.lastName}`.trim()
}}
@ -1313,7 +1322,7 @@ watch(
:data="{
code: props.row.code,
name:
$i18n.locale === 'eng'
locale === 'eng'
? `${props.row.firstNameEN} ${props.row.lastNameEN}`.trim()
: `${props.row.firstName} ${props.row.lastName}`.trim(),
img: props.row.profileImageUrl
@ -1501,7 +1510,7 @@ watch(
hide-action
:isEdit="infoDrawerEdit"
:title="
$i18n.locale === 'eng'
locale === 'eng'
? `${currentUser.firstNameEN} ${currentUser.lastNameEN}`
: `${currentUser.firstName} ${currentUser.lastName}`
"
@ -1530,7 +1539,7 @@ watch(
hideFade
:menu="formMenuIcon"
:toggleTitle="$t('status.title')"
:title="`${$i18n.locale === 'eng' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
:title="`${locale === 'eng' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
:caption="userCode"
:img="
`${baseUrl}/user/${currentUser.id}/profile-image/${formData.selectedImage}`.concat(
@ -1556,7 +1565,8 @@ watch(
@edit="imageDialog = isImageEdit = true"
@update:toggle-status="
async (v) => {
await triggerChangeStatus(infoPersonId, v);
if (!currentUser) return;
await triggerChangeStatus(currentUser.id, v);
}
"
/>
@ -1609,7 +1619,12 @@ watch(
v-if="!infoDrawerEdit"
id="btn-info-basic-delete"
icon-only
@click="() => onDelete(infoPersonId)"
@click="
() => {
if (!currentUser) return;
onDelete(currentUser.id);
}
"
type="button"
/>
</div>
@ -1692,6 +1707,9 @@ watch(
v-model:email="formData.email"
v-model:gender="formData.gender"
v-model:birth-date="formData.birthDate"
v-model:citizen-id="formData.citizenId"
v-model:citizen-issue="formData.citizenIssue"
v-model:citizen-expire="formData.citizenExpire"
:title="'personnel.form.personalInformation'"
prefix-id="drawer-info-personnel"
dense
@ -1705,6 +1723,12 @@ watch(
id="info-address"
v-model:address="formData.address"
v-model:addressEN="formData.addressEN"
v-model:moo="formData.moo"
v-model:mooEN="formData.mooEN"
v-model:soi="formData.soi"
v-model:soiEN="formData.soiEN"
v-model:street="formData.street"
v-model:streetEN="formData.streetEN"
v-model:provinceId="formData.provinceId"
v-model:districtId="formData.districtId"
v-model:subDistrictId="formData.subDistrictId"
@ -1734,7 +1758,7 @@ watch(
v-model:checkpointEN="formData.checkpointEN"
v-model:agencyFile="agencyFile"
v-model:agencyFileList="agencyFileList"
v-model:userId="userId"
v-model:userId="currentUser.id"
/>
</div>
</div>
@ -1746,7 +1770,6 @@ watch(
<DialogForm
hideFooter
removeDialog
ref="formDialogRef"
:badgeClass="formData.gender === 'male' ? 'app-bg-male' : 'app-bg-female'"
:badgeLabel="userCode"
:title="$t('personnel.addTitle')"
@ -1774,7 +1797,7 @@ watch(
}[formData.gender]
"
:toggleTitle="$t('status.title')"
:title="`${$i18n.locale === 'eng' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
:title="`${locale === 'eng' ? `${formData.firstNameEN} ${formData.lastNameEN}` : `${formData.firstName} ${formData.lastName}`}`"
:fallbackImg="
{
male: '/no-img-man.png',
@ -1880,12 +1903,21 @@ watch(
v-model:email="formData.email"
v-model:gender="formData.gender"
v-model:birth-date="formData.birthDate"
v-model:citizen-id="formData.citizenId"
v-model:citizen-issue="formData.citizenIssue"
v-model:citizen-expire="formData.citizenExpire"
class="q-mb-xl"
/>
<AddressForm
id="dialog-form-address"
v-model:address="formData.address"
v-model:addressEN="formData.addressEN"
v-model:moo="formData.moo"
v-model:mooEN="formData.mooEN"
v-model:soi="formData.soi"
v-model:soiEN="formData.soiEN"
v-model:street="formData.street"
v-model:streetEN="formData.streetEN"
v-model:provinceId="formData.provinceId"
v-model:districtId="formData.districtId"
v-model:subDistrictId="formData.subDistrictId"
@ -1916,9 +1948,7 @@ watch(
</div>
</DialogForm>
<!-- :default-url="`${baseUrl}/user/${currentUser?.id}/image`" -->
<ImageUploadDialog
ref="refImageUpload"
v-model:dialogState="imageDialog"
v-model:file="profileFileImg"
v-model:image-url="urlProfile"
@ -1969,7 +1999,7 @@ watch(
<span v-if="!modal" class="justify-center flex text-bold">
{{ $t('general.image') }}
{{
$i18n.locale === 'eng'
locale === 'eng'
? `${formData.firstNameEN} ${formData.lastNameEN}`
: `${formData.firstName} ${formData.lastName}`
}}

View file

@ -34,6 +34,12 @@ export type User = {
provinceId: string | null;
addressEN: string;
address: string;
mooEN: string;
moo: string;
soiEN: string;
soi: string;
streetEN: string;
street: string;
lastNameEN: string;
lastName: string;
middleNameEN?: string | null;
@ -47,6 +53,9 @@ export type User = {
responsibleArea: string;
checkpoint?: string | null;
checkpointEN?: string | null;
citizenExpire?: Date | null;
citizenIssue?: Date | null;
citizenId: string;
branch: Branch[];
};
@ -62,6 +71,12 @@ export type UserCreate = {
gender: string;
addressEN: string;
address: string;
mooEN: string;
moo: string;
soiEN: string;
soi: string;
streetEN: string;
street: string;
trainingPlace?: string | null;
importNationality?: string | null;
sourceNationality?: string | null;
@ -87,6 +102,9 @@ export type UserCreate = {
responsibleArea?: string | null;
checkpoint?: string | null;
checkpointEN?: string | null;
citizenExpire?: Date | null;
citizenIssue?: Date | null;
citizenId: string;
};
export type UserAttachment = {