refactor: worker select & employee nationality

This commit is contained in:
puriphatt 2024-10-03 18:10:40 +07:00
parent 8006314ce4
commit 9d745d8e52
5 changed files with 100 additions and 52 deletions

View file

@ -258,7 +258,7 @@ defineEmits<{
detail: [ detail: [
{ {
icon: 'mdi-passport', icon: 'mdi-passport',
value: props.row.nationality, value: optionStore.mapOption(props.row.nationality),
}, },
{ {

View file

@ -9,6 +9,7 @@ defineEmits<{
withDefaults( withDefaults(
defineProps<{ defineProps<{
employeeAmount: number; employeeAmount: number;
fallbackImg?: string;
rows: { rows: {
foreignRefNo: string; foreignRefNo: string;
employeeName: string; employeeName: string;
@ -92,7 +93,11 @@ const columns = [
> >
<template v-slot:img-column="{ props }"> <template v-slot:img-column="{ props }">
<q-avatar class="q-mr-sm" size="md"> <q-avatar class="q-mr-sm" size="md">
<q-img :src="props.row.imgUrl"></q-img> <q-img :src="props.row.imgUrl" class="full-height full-width">
<template #error>
<q-img :src="fallbackImg" :ratio="1" />
</template>
</q-img>
<div <div
class="absolute-bottom-right" class="absolute-bottom-right"
style=" style="
@ -121,7 +126,7 @@ const columns = [
class="surface-tab bordered rounded flex items-center justify-center q-mx-md" class="surface-tab bordered rounded flex items-center justify-center q-mx-md"
style="width: 30px; height: 30px" style="width: 30px; height: 30px"
> >
{{ employeeAmount }} {{ employeeAmount || '0' }}
</div> </div>
</div> </div>
</div> </div>

View file

@ -21,7 +21,7 @@ const props = withDefaults(
}, },
); );
defineExpose({ select }); defineExpose({ select, assignSelect });
function select(item?: unknown, all?: boolean) { function select(item?: unknown, all?: boolean) {
if (all) { if (all) {
@ -44,6 +44,19 @@ function select(item?: unknown, all?: boolean) {
} else selectedItem.value.push(item); } else selectedItem.value.push(item);
} }
} }
function assignSelect(to: unknown[], from: unknown[]) {
const existingItems = new Set(to);
for (let i = to.length - 1; i >= 0; i--) {
if (!from.includes(to[i])) {
to.splice(i, 1);
}
}
const newItems = from.filter((item) => !existingItems.has(item));
to.push(...newItems);
}
</script> </script>
<template> <template>
<section class="full-width column"> <section class="full-width column">

View file

@ -2,12 +2,13 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { QSelect, useQuasar } from 'quasar'; import { QSelect, useQuasar } from 'quasar';
import { onMounted, reactive, ref } from 'vue'; import { nextTick, onMounted, reactive, ref } from 'vue';
import { setLocale } from 'src/utils/datetime'; import { baseUrl } from 'src/stores/utils';
import { dateFormat } from 'src/utils/datetime'; import { setLocale, dateFormat, calculateAge } from 'src/utils/datetime';
import useOptionStore from 'stores/options'; import useOptionStore from 'stores/options';
import useEmployeeStore from 'src/stores/employee';
import { useQuotationForm } from './form'; import { useQuotationForm } from './form';
import { Employee } from 'src/stores/employee/types'; import { Employee } from 'src/stores/employee/types';
import { import {
@ -28,6 +29,7 @@ import SelectZone from 'src/components/shared/SelectZone.vue';
import PersonCard from 'src/components/shared/PersonCard.vue'; import PersonCard from 'src/components/shared/PersonCard.vue';
import { AddButton, SaveButton } from 'components/button'; import { AddButton, SaveButton } from 'components/button';
import useProductServiceStore from 'src/stores/product-service'; import useProductServiceStore from 'src/stores/product-service';
import useCustomerStore from 'src/stores/customer';
type Node = { type Node = {
[key: string]: any; [key: string]: any;
@ -44,20 +46,26 @@ defineProps<{
}>(); }>();
const optionStore = useOptionStore(); const optionStore = useOptionStore();
const customerStore = useCustomerStore();
const productServiceStore = useProductServiceStore(); const productServiceStore = useProductServiceStore();
const quotationForm = useQuotationForm(); const quotationForm = useQuotationForm();
const employeeStore = useEmployeeStore();
const { locale } = useI18n(); const { locale } = useI18n();
const { currentFormData: quotationFormData } = storeToRefs(quotationForm); const { currentFormData: quotationFormData } = storeToRefs(quotationForm);
const $q = useQuasar(); const $q = useQuasar();
const refSelectZoneEmployee = ref<InstanceType<typeof SelectZone>>();
const date = ref(); const date = ref();
const rows = ref<Node[]>([]); const rows = ref<Node[]>([]);
const selectedEmployee = ref<Employee[]>([]);
const selectedBranchIssuer = ref(''); const selectedBranchIssuer = ref('');
const selectedCustomer = ref(''); const selectedCustomer = ref('');
const toggleWorker = ref(true); const toggleWorker = ref(true);
const branchId = ref(''); const branchId = ref('');
const selectedWorker = ref<Employee[]>([]);
const preSelectedWorker = ref<Employee[]>([]);
const workerList = ref<Employee[]>([]);
const quotationNo = ref(''); const quotationNo = ref('');
const actor = ref(''); const actor = ref('');
const workName = ref(''); const workName = ref('');
@ -130,9 +138,13 @@ async function getAllService(
if (ret) serviceList.value[groupId] = ret.result; if (ret) serviceList.value[groupId] = ret.result;
} }
function triggerSelectEmployeeDialog() { async function triggerSelectEmployeeDialog() {
pageState.employeeModal = true; pageState.employeeModal = true;
// TODO: form and state controll await nextTick();
refSelectZoneEmployee.value?.assignSelect(
preSelectedWorker.value,
selectedWorker.value,
);
} }
function triggerProductServiceDialog() { function triggerProductServiceDialog() {
@ -153,6 +165,14 @@ function convertToTable(nodes: Node[]) {
productServiceList.value = nodes.flatMap(_recursive).map((v) => v.value); productServiceList.value = nodes.flatMap(_recursive).map((v) => v.value);
} }
function convertEmployeeToTable() {
refSelectZoneEmployee.value?.assignSelect(
selectedWorker.value,
preSelectedWorker.value,
);
pageState.employeeModal = false;
}
function changeMode(mode: string) { function changeMode(mode: string) {
if (mode === 'light') { if (mode === 'light') {
localStorage.setItem('currentTheme', 'light'); localStorage.setItem('currentTheme', 'light');
@ -199,6 +219,11 @@ onMounted(async () => {
if (locale.value === 'eng') optionStore.globalOption = rawOption.eng; if (locale.value === 'eng') optionStore.globalOption = rawOption.eng;
if (locale.value === 'tha') optionStore.globalOption = rawOption.tha; if (locale.value === 'tha') optionStore.globalOption = rawOption.tha;
const retEmp = await customerStore.fetchBranchEmployee(
quotationFormData.value.customerBranchId,
);
if (retEmp) workerList.value = retEmp.data.result;
const getCurLang = localStorage.getItem('currentLanguage'); const getCurLang = localStorage.getItem('currentLanguage');
if (getCurLang === 'English') { if (getCurLang === 'English') {
locale.value = 'eng'; locale.value = 'eng';
@ -307,19 +332,24 @@ onMounted(async () => {
<div class="surface-1 q-pa-md full-width"> <div class="surface-1 q-pa-md full-width">
<WorkerItem <WorkerItem
:rows="[ :employee-amount="selectedWorker.length"
{ fallback-img="/images/employee-avatar.png"
foreignRefNo: '123', :rows="
employeeName: '123', selectedWorker.map((e: Employee) => ({
birthDate: '123', foreignRefNo: '123456789',
gender: '123', employeeName:
age: '123', $i18n.locale === 'eng'
nationality: '123', ? `${e.firstNameEN} ${e.lastNameEN}`
documentExpireDate: '123', : `${e.firstName} ${e.lastName}`,
imgUrl: '/images/employee-avatar.png', birthDate: dateFormat(e.dateOfBirth),
status: 'ACTIVE', gender: e.gender,
}, age: calculateAge(e.dateOfBirth),
]" nationality: optionStore.mapOption(e.nationality),
documentExpireDate: '1234',
imgUrl: `${baseUrl}/customer/${e.id}/image/${e.selectedImage}`,
status: e.status,
}))
"
/> />
</div> </div>
</q-expansion-item> </q-expansion-item>
@ -448,33 +478,18 @@ onMounted(async () => {
:submit-label="$t('general.select', { msg: $t('quotation.employee') })" :submit-label="$t('general.select', { msg: $t('quotation.employee') })"
submit-icon="mdi-check" submit-icon="mdi-check"
height="75vh" height="75vh"
:submit="() => convertEmployeeToTable()"
:close="
() => {
(preSelectedWorker = []), (pageState.employeeModal = false);
}
"
> >
<section class="col row scroll"> <section class="col row scroll">
<SelectZone <SelectZone
v-model:selected-item="selectedEmployee" ref="refSelectZoneEmployee"
:items="[ v-model:selected-item="preSelectedWorker"
{ :items="workerList"
name: 'มิเคล่า สุวรรณดี',
gender: 'female',
telephoneNo: '0621249602',
code: 'CORP000000-1-01-240001',
birthDate: '16 ปี 11 เดือน 5 วัน',
},
{
name: 'มิลิเซนต์ สุวรรณดี',
gender: 'female',
telephoneNo: '0621249666',
code: 'CORP000000-1-01-240002',
birthDate: '19 ปี 2 เดือน 2 วัน',
},
{
name: 'ไรคาร์ด พวงศรี',
gender: 'male',
telephoneNo: '0621249777',
code: 'CORP000000-1-01-240003',
birthDate: '39 ปี 5 เดือน 2 วัน',
},
]"
> >
<template #top> <template #top>
<AddButton <AddButton
@ -492,14 +507,24 @@ onMounted(async () => {
prefixId="asda" prefixId="asda"
class="full-width" class="full-width"
:data="{ :data="{
name: item.name, name:
$i18n.locale === 'eng'
? `${item.firstNameEN} ${item.lastNameEN}`
: `${item.firstName} ${item.lastName}`,
code: item.code, code: item.code,
female: item.gender === 'female', female: item.gender === 'female',
male: item.gender === 'male', male: item.gender === 'male',
img: '/images/employee-avatar.png', img: `${baseUrl}/customer/${item.id}/image/${item.selectedImage}`,
fallbackImg: '/images/employee-avatar.png',
detail: [ detail: [
{ icon: 'mdi-phone-outline', value: item.telephoneNo }, {
{ icon: 'mdi-clock-outline', value: item.birthDate }, icon: 'mdi-passport',
value: optionStore.mapOption(item.nationality),
},
{
icon: 'mdi-clock-outline',
value: calculateAge(item.dateOfBirth),
},
], ],
}" }"
></PersonCard> ></PersonCard>

View file

@ -21,7 +21,7 @@ export function dateFormat(
if (time) return m.format('HH:mm'); if (time) return m.format('HH:mm');
if (number) { if (number) {
let formattedNumberDate = m.format('L'); const formattedNumberDate = m.format('L');
return formattedNumberDate; return formattedNumberDate;
} }
@ -60,6 +60,11 @@ export function toISOStringWithTimezone(date: Date) {
); );
} }
export function calculateAge(birthDate: Date | null | string): string;
export function calculateAge(
birthDate: Date | null | string,
only: 'year' | 'months' | 'days',
): number;
export function calculateAge( export function calculateAge(
birthDate: Date | null | string, birthDate: Date | null | string,
only?: 'year' | 'months' | 'days', only?: 'year' | 'months' | 'days',