fix: product worker

This commit is contained in:
puriphatt 2024-10-09 18:09:01 +07:00
parent f4802b6991
commit 7f0d006a7c
4 changed files with 176 additions and 248 deletions

View file

@ -5,6 +5,8 @@ import ThaiBahtText from 'thai-baht-text';
import { toWords } from 'number-to-words'; import { toWords } from 'number-to-words';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import WorkerItem from './WorkerItem.vue';
import DeleteButton from '../button/DeleteButton.vue';
import { commaInput } from 'stores/utils'; import { commaInput } from 'stores/utils';
import { precisionRound } from 'src/utils/arithmetic'; import { precisionRound } from 'src/utils/arithmetic';
import TableComponents from 'components/TableComponents.vue'; import TableComponents from 'components/TableComponents.vue';
@ -15,6 +17,17 @@ import { Product, Service, Work } from 'src/stores/product-service/types';
defineProps<{ defineProps<{
agentPrice: boolean; agentPrice: boolean;
employeeRows?: {
foreignRefNo: string;
employeeName: string;
birthDate: string;
gender: string;
age: string;
nationality: string;
documentExpireDate: string;
imgUrl: string;
status: string;
}[];
}>(); }>();
defineEmits<{ defineEmits<{
@ -59,7 +72,9 @@ const summaryPrice = defineModel<{
}, },
}); });
const currentBtnOpen = ref<boolean[]>([]); const currentBtnOpen = ref<{ title: string; opened: boolean[] }[]>([
{ title: '', opened: [] },
]);
const finalDiscount = ref<number>(0); const finalDiscount = ref<number>(0);
const finalDiscount4Show = ref<string>(finalDiscount.value.toString()); const finalDiscount4Show = ref<string>(finalDiscount.value.toString());
@ -104,7 +119,7 @@ const columns = [
}, },
{ {
name: 'code', name: 'code',
align: 'center', align: 'left',
label: 'productService.group.code', label: 'productService.group.code',
field: (v) => v.product.code, field: (v) => v.product.code,
}, },
@ -150,12 +165,6 @@ const columns = [
label: 'quotation.sumPrice', label: 'quotation.sumPrice',
field: 'sumPrice', field: 'sumPrice',
}, },
{
name: 'action',
align: 'left',
label: '',
field: 'action',
},
] satisfies QTableProps['columns']; ] satisfies QTableProps['columns'];
const EngBahtText = (number: number) => { const EngBahtText = (number: number) => {
@ -167,14 +176,16 @@ const EngBahtText = (number: number) => {
return `${bahtText} Baht${satang ? ` and ${satangText} Satang` : ''}`; return `${bahtText} Baht${satang ? ` and ${satangText} Satang` : ''}`;
}; };
function openEmployeeTable(index: number) { function openEmployeeTable(title: string, index: number) {
currentBtnOpen.value.map((_, i) => { currentBtnOpen.value[0].title = title;
currentBtnOpen.value[0].opened.map((_, i) => {
if (i !== index) { if (i !== index) {
currentBtnOpen.value[i] = false; currentBtnOpen.value[0].opened[i] = false;
} }
}); });
currentBtnOpen.value[index] = !currentBtnOpen.value[index]; currentBtnOpen.value[0].opened[index] =
!currentBtnOpen.value[0].opened[index];
} }
watch( watch(
@ -202,25 +213,29 @@ watch(
</q-avatar> </q-avatar>
{{ item.title }} {{ item.title }}
</div> </div>
<TableComponents
<q-table
flat flat
bordered bordered
hidePagination hide-pagination
button-delete
:columns="columns" :columns="columns"
:rows="item.product" :rows="item.product"
:customColumn="[ class="full-width"
'name', :no-data-label="$t('general.noDataTable')"
'amount',
'pricePerUnit',
'discount',
'tax',
'sumPrice',
'priceBeforeVat',
]"
@delete="(i) => $emit('delete', i)"
> >
<template v-slot:body-cell-name="{ props }"> <template #header="{ cols }">
<q-tr style="background-color: hsla(var(--info-bg) / 0.07)">
<q-th v-for="(v, i) in cols" :key="v">
{{ $t(v.label) }}
</q-th>
<q-th auto-width />
</q-tr>
</template>
<template #body="props">
<q-tr>
<q-td class="text-center">{{ props.rowIndex + 1 }}</q-td>
<q-td>{{ props.row.product.code }}</q-td>
<q-td> <q-td>
<q-avatar class="q-mr-sm" size="md"> <q-avatar class="q-mr-sm" size="md">
<q-icon <q-icon
@ -231,9 +246,6 @@ watch(
</q-avatar> </q-avatar>
{{ props.row.product.name }} {{ props.row.product.name }}
</q-td> </q-td>
</template>
<template v-slot:body-cell-amount="{ props }">
<q-td align="center"> <q-td align="center">
<q-input <q-input
dense dense
@ -244,9 +256,6 @@ watch(
v-model="props.row.amount" v-model="props.row.amount"
/> />
</q-td> </q-td>
</template>
<template v-slot:body-cell-pricePerUnit="{ props }">
<q-td align="right"> <q-td align="right">
{{ {{
formatNumberDecimal( formatNumberDecimal(
@ -256,9 +265,6 @@ watch(
) )
}} }}
</q-td> </q-td>
</template>
<template v-slot:body-cell-discount="{ props }">
<q-td align="center"> <q-td align="center">
<q-input <q-input
dense dense
@ -270,35 +276,28 @@ watch(
v-model="props.row.discount" v-model="props.row.discount"
/> />
</q-td> </q-td>
</template>
<template v-slot:body-cell-priceBeforeVat="{ props }">
<q-td align="right"> <q-td align="right">
{{ formatNumberDecimal(props.row.pricePerUnit, 2) }} {{ formatNumberDecimal(props.row.pricePerUnit, 2) }}
</q-td> </q-td>
</template>
<template v-slot:body-cell-tax="{ props }">
<q-td align="right"> <q-td align="right">
{{ {{
formatNumberDecimal(
precisionRound( precisionRound(
(props.row.pricePerUnit * props.row.amount - (props.row.pricePerUnit * props.row.amount -
props.row.discount) * props.row.discount) *
(config?.vat || 0.07), (config?.vat || 0.07),
),
2,
) )
}} }}
</q-td> </q-td>
</template>
<template v-slot:body-cell-sumPrice="{ props }">
<q-td align="right"> <q-td align="right">
{{ formatNumberDecimal(calcPrice(props.row), 2) }} {{ formatNumberDecimal(calcPrice(props.row), 2) }}
</q-td> </q-td>
</template> <q-td>
<div class="row items-center full-width justify-end no-wrap">
<template #button="{ props }">
<q-btn <q-btn
@click.stop="openEmployeeTable(props.rowIndex)" @click.stop="openEmployeeTable(item.title, props.rowIndex)"
dense dense
flat flat
size="sm" size="sm"
@ -308,7 +307,7 @@ watch(
<q-icon name="mdi-account-group-outline" /> <q-icon name="mdi-account-group-outline" />
<q-icon <q-icon
size="xs" size="xs"
:name="`mdi-chevron-${currentBtnOpen[props.rowIndex] ? 'down' : 'up'}`" :name="`mdi-chevron-${currentBtnOpen[0].title === item.title && currentBtnOpen[0].opened[props.rowIndex] ? 'down' : 'up'}`"
/> />
</div> </div>
</q-btn> </q-btn>
@ -324,129 +323,34 @@ watch(
color: hsl(var(--positive-bg)); color: hsl(var(--positive-bg));
" "
/> />
<DeleteButton
iconOnly
@click="$emit('delete', props.rowIndex)"
/>
</div>
</q-td>
</q-tr>
<q-tr
v-show="
currentBtnOpen[0].title === item.title &&
currentBtnOpen[0].opened[props.rowIndex]
"
:props="props"
>
<q-td colspan="100%" style="padding: 16px">
<WorkerItem
fallback-img="/images/employee-avatar.png"
inTable
hideQuantity
:rows="employeeRows"
/>
</q-td>
</q-tr>
</template> </template>
</TableComponents> </q-table>
</section> </section>
</div> </div>
<div class="row items-start">
<span
class="col row items-center justify-between q-px-md q-py-xs q-mr-lg rounded app-text-muted-2 bg-color-orange-light"
>
<span class="text-weight-bold text-caption">
{{ $t('general.totalAmount') }}
</span>
<span v-if="summary.finalPrice + Number(finalDiscount)">
{{
$i18n.locale === 'eng'
? EngBahtText(summary.finalPrice)
: ThaiBahtText(summary.finalPrice)
}}
</span>
</span>
<div class="col column">
<div class="row q-py-xs q-pr-xs q-pl-md">
<span class="col-9 app-text-muted-2">
{{ $t('quotation.allProductPrice') }}
</span>
<q-input
dense
class="col price-tag"
readonly
outlined
input-class="text-right text-bold "
:model-value="
formatNumberDecimal(summary.finalPrice + Number(finalDiscount), 2)
"
/>
</div>
<div class="row q-py-xs q-pr-xs q-pl-md">
<span class="col-9 app-text-muted-2">
{{ $t('quotation.quotationDiscount') }}
</span>
<q-input
dense
class="col price-tag"
outlined
input-class="text-right text-bold"
:model-value="commaInput(finalDiscount.toString())"
@update:model-value="
(v) => {
if (typeof v === 'string') finalDiscount4Show = commaInput(v);
const x = parseFloat(
finalDiscount4Show && typeof finalDiscount4Show === 'string'
? finalDiscount4Show.replace(/,/g, '')
: '',
);
finalDiscount = x;
}
"
/>
</div>
<div
class="row text-bold bg-color-orange rounded q-py-xs q-pr-xs q-pl-md items-center"
style="color: var(--surface-1)"
>
<span class="col-9">
{{ $t('general.totalAmount') }}
</span>
<q-input
dense
class="col price-tag"
outlined
readonly
input-class="text-right text-bold "
:model-value="
formatNumberDecimal(Math.max(summary.finalPrice, 0), 2)
"
/>
</div>
</div>
</div>
<!-- <div
class="column q-ml-auto text-caption app-text-muted-2"
style="width: 15vw"
>
<div class="row">
{{ $t('quotation.allProductPrice') }}
<span class="q-ml-auto">
{{ formatNumberDecimal(summary.totalPrice, 2) }} ฿
</span>
</div>
<div class="row">
{{ $t('general.discount') }}
<span class="q-ml-auto">
{{ formatNumberDecimal(summary.totalDiscount, 2) }} ฿
</span>
</div>
<div class="row">
{{ $t('quotation.tax') }}
<span class="q-ml-auto">
{{ formatNumberDecimal(summary.vat, 2) }} ฿
</span>
</div>
<q-separator spaced="md" />
<div class="row text-bold text-body2" style="color: var(--foreground)">
{{ $t('quotation.totalPrice') }}
<span class="q-ml-auto">
{{ formatNumberDecimal(summary.finalPrice, 2) }} ฿
</span>
</div>
</div>
<span
v-if="summary.finalPrice"
class="text-caption app-text-muted-2 flex self-end"
>
({{
$i18n.locale === 'eng'
? EngBahtText(summary.finalPrice)
: ThaiBahtText(summary.finalPrice)
}})
</span> -->
</div> </div>
</template> </template>
@ -495,4 +399,8 @@ watch(
bottom: 0; bottom: 0;
background: var(--side-color); background: var(--side-color);
} }
:deep(i.q-icon.mdi.mdi-alert.q-table__bottom-nodata-icon) {
color: #ffc224 !important;
}
</style> </style>

View file

@ -10,6 +10,8 @@ withDefaults(
defineProps<{ defineProps<{
employeeAmount: number; employeeAmount: number;
fallbackImg?: string; fallbackImg?: string;
hideQuantity?: boolean;
inTable?: boolean;
rows: { rows: {
foreignRefNo: string; foreignRefNo: string;
employeeName: string; employeeName: string;
@ -86,6 +88,7 @@ const columns = [
bordered bordered
button-delete button-delete
img-column="employeeName" img-column="employeeName"
:inTable
:columns :columns
:rows :rows
hidePagination hidePagination
@ -118,7 +121,7 @@ const columns = [
</template> </template>
</TableComponents> </TableComponents>
<div class="row q-pt-md items-center"> <div v-if="!hideQuantity" class="row q-pt-md items-center">
<span class="q-ml-auto"> <span class="q-ml-auto">
{{ $t('general.numberOf', { msg: $t('quotation.employee') }) }} {{ $t('general.numberOf', { msg: $t('quotation.employee') }) }}
</span> </span>

View file

@ -14,6 +14,7 @@ const props = withDefaults(
buttomDownload?: boolean; buttomDownload?: boolean;
buttonDelete?: boolean; buttonDelete?: boolean;
hidePagination?: boolean; hidePagination?: boolean;
inTable?: boolean;
imgColumn?: string; imgColumn?: string;
customColumn?: string[]; customColumn?: string[];
@ -52,7 +53,7 @@ defineEmits<{
> >
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr <q-tr
style="background-color: hsla(var(--info-bg) / 0.07)" :style="`background-color: ${inTable ? '#F0FFF1' : 'hsla(var(--info-bg) / 0.07'} `"
:props="props" :props="props"
> >
<q-th v-for="col in props.cols" :key="col.name" :props="props"> <q-th v-for="col in props.cols" :key="col.name" :props="props">

View file

@ -688,6 +688,22 @@ watch(
<ProductItem <ProductItem
:agent-price="agentPrice" :agent-price="agentPrice"
:employeeRows="
selectedWorker.map((e: Employee) => ({
foreignRefNo: '123456789',
employeeName:
$i18n.locale === 'eng'
? `${e.firstNameEN} ${e.lastNameEN}`
: `${e.firstName} ${e.lastName}`,
birthDate: dateFormat(e.dateOfBirth),
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,
}))
"
@delete="toggleDeleteProduct" @delete="toggleDeleteProduct"
v-model:groupList="productServiceTableData" v-model:groupList="productServiceTableData"
v-model:rows="productServiceList" v-model:rows="productServiceList"