refactor: worker select & employee nationality
This commit is contained in:
parent
8006314ce4
commit
9d745d8e52
5 changed files with 100 additions and 52 deletions
|
|
@ -258,7 +258,7 @@ defineEmits<{
|
||||||
detail: [
|
detail: [
|
||||||
{
|
{
|
||||||
icon: 'mdi-passport',
|
icon: 'mdi-passport',
|
||||||
value: props.row.nationality,
|
value: optionStore.mapOption(props.row.nationality),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue