feat: add select product service function to form

This commit is contained in:
Methapon Metanipat 2024-10-03 17:17:15 +07:00
parent af0a66347c
commit f73aa84336
2 changed files with 87 additions and 68 deletions

View file

@ -1,38 +1,49 @@
<script lang="ts" setup> <script lang="ts" setup>
import { QTableProps } from 'quasar'; import { QTableProps } from 'quasar';
import TableComponents from 'src/components/TableComponents.vue'; import TableComponents from 'src/components/TableComponents.vue';
import { QuotationPayload } from 'src/stores/quotations/types';
import { computed } from 'vue';
const calTax = defineModel('calTax', { default: false }); const calTax = defineModel('calTax', { default: false });
const priceData = defineModel<{
productList: number;
discount: number;
tax: number;
totalPrice: number;
}>('priceData', {
default: { productList: 0, discount: 0, tax: 0, totalPrice: 0 },
});
defineEmits<{ defineEmits<{
(e: 'delete', index: number): void; (e: 'delete', index: number): void;
}>(); }>();
withDefaults( const rows = defineModel<
defineProps<{ Required<QuotationPayload['productServiceList'][number]>[]
rows: { >('rows', { required: true });
[key: string]: any;
code: string; function calcPrice(data: (typeof rows.value)[number]) {
name: string; const price = data.pricePerUnit * data.amount;
type: string; const discount = Math.round(price * data.discount) / 100;
amount: number; const vat = Math.round((price - discount) * data.vat) / 100;
pricePerUnit: number;
discount: number; return (price * 100 - discount * 100 + vat * 100) / 100;
tax: number; }
sumPrice: number;
}[]; const summary = computed(() =>
}>(), rows.value.reduce(
{ (a, c) => {
rows: () => [], const price = c.pricePerUnit * c.amount;
}, const discount = Math.round(price * c.discount) / 100;
const vat = Math.round((price - discount) * c.vat) / 100;
a.totalPrice = (a.totalPrice * 100 + price * 100) / 100;
a.totalDiscount = (a.totalDiscount * 100 + discount * 100) / 100;
a.vat = (a.vat * 100 + vat * 100) / 100;
a.finalPrice =
(a.finalPrice * 100 + price * 100 - discount * 100 + vat * 100) / 100;
return a;
},
{
totalPrice: 0,
totalDiscount: 0,
vat: 0,
finalPrice: 0,
},
),
); );
const columns = [ const columns = [
@ -46,13 +57,13 @@ const columns = [
name: 'code', name: 'code',
align: 'center', align: 'center',
label: 'productService.group.code', label: 'productService.group.code',
field: 'code', field: (v) => v.product.code,
}, },
{ {
name: 'name', name: 'name',
align: 'left', align: 'left',
label: 'productService.service.list', label: 'productService.service.list',
field: 'name', field: (v) => v.product.name,
}, },
{ {
name: 'amount', name: 'amount',
@ -101,18 +112,27 @@ const columns = [
button-delete button-delete
:columns="columns" :columns="columns"
:rows="rows" :rows="rows"
imgColumn="name" :customColumn="[
:customColumn="['amount', 'pricePerUnit', 'discount', 'tax', 'sumPrice']" 'name',
'amount',
'pricePerUnit',
'discount',
'tax',
'sumPrice',
]"
@delete="(i) => $emit('delete', i)" @delete="(i) => $emit('delete', i)"
> >
<template v-slot:img-column="{ props }"> <template v-slot:body-cell-name="{ props }">
<q-avatar class="q-mr-sm" size="md"> <div>
<q-icon <q-avatar class="q-mr-sm" size="md">
class="full-width full-height" <q-icon
name="mdi-shopping-outline" class="full-width full-height"
:style="`color: var(--teal-10); background: hsla(var(--teal-${$q.dark.isActive ? '8' : '10'}-hsl)/0.15)`" name="mdi-shopping-outline"
/> :style="`color: var(--teal-10); background: hsla(var(--teal-${$q.dark.isActive ? '8' : '10'}-hsl)/0.15)`"
</q-avatar> />
</q-avatar>
{{ props.row.product.name }}
</div>
</template> </template>
<template v-slot:body-cell-amount="{ props }"> <template v-slot:body-cell-amount="{ props }">
@ -123,8 +143,7 @@ const columns = [
type="number" type="number"
style="width: 70px" style="width: 70px"
min="0" min="0"
:modelValue="props.row.amount" v-model="props.row.amount"
@update:modelValue="(v) => (props.row = v)"
/> />
</q-td> </q-td>
</template> </template>
@ -136,9 +155,8 @@ const columns = [
outlined outlined
type="number" type="number"
style="width: 70px" style="width: 70px"
:modelValue="props.row.pricePerUnit"
min="0" min="0"
@update:modelValue="(v) => (props.row = v)" v-model="props.row.pricePerUnit"
/> />
</q-td> </q-td>
</template> </template>
@ -151,9 +169,12 @@ const columns = [
outlined outlined
type="number" type="number"
style="width: 70px" style="width: 70px"
:modelValue="props.row.discount" v-model="props.row.discount"
@update:modelValue="(v) => (props.row = v)" >
/> <template v-slot:append>
<span class="text-caption no-padding">%</span>
</template>
</q-input>
</q-td> </q-td>
</template> </template>
@ -165,8 +186,7 @@ const columns = [
outlined outlined
type="number" type="number"
style="width: 70px" style="width: 70px"
:modelValue="props.row.tax" v-model="props.row.vat"
@update:modelValue="(v) => (props.row = v)"
> >
<template v-slot:append> <template v-slot:append>
<span class="text-caption no-padding">%</span> <span class="text-caption no-padding">%</span>
@ -177,15 +197,7 @@ const columns = [
<template v-slot:body-cell-sumPrice="{ props }"> <template v-slot:body-cell-sumPrice="{ props }">
<q-td align="center"> <q-td align="center">
<q-input {{ calcPrice(props.row) }}
dense
min="0"
outlined
type="number"
style="width: 70px"
:modelValue="props.row.sumPrice"
@update:modelValue="(v) => (props.row = v)"
/>
</q-td> </q-td>
</template> </template>
@ -215,21 +227,21 @@ const columns = [
style="width: 15vw" style="width: 15vw"
> >
<div class="row"> <div class="row">
{{ $t('quotation.allProduct') }} {{ $t('quotation.price') }}
<span class="q-ml-auto">{{ priceData.productList }} ฿</span> <span class="q-ml-auto">{{ summary.totalPrice }} ฿</span>
</div> </div>
<div class="row"> <div class="row">
{{ $t('general.discount') }} {{ $t('general.discount') }}
<span class="q-ml-auto">{{ priceData.discount }} ฿</span> <span class="q-ml-auto">{{ summary.totalDiscount }} ฿</span>
</div> </div>
<div class="row"> <div class="row">
{{ $t('quotation.tax') }} {{ $t('quotation.tax') }}
<span class="q-ml-auto">{{ priceData.tax }} ฿</span> <span class="q-ml-auto">{{ summary.vat }} ฿</span>
</div> </div>
<q-separator spaced="md" /> <q-separator spaced="md" />
<div class="row text-bold text-body2" style="color: var(--foreground)"> <div class="row text-bold text-body2" style="color: var(--foreground)">
Total Price Total Price
<span class="q-ml-auto">{{ priceData.totalPrice }} ฿</span> <span class="q-ml-auto">{{ summary.finalPrice }} ฿</span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -97,6 +97,10 @@ const selectedGroup = ref<ProductGroup | null>(null);
const selectedGroupSub = ref<'product' | 'service' | null>(null); const selectedGroupSub = ref<'product' | 'service' | null>(null);
const selectedProductServiceId = ref(''); const selectedProductServiceId = ref('');
const productServiceList = ref<
Required<QuotationPayload['productServiceList'][number]>[]
>([]);
async function getAllProduct( async function getAllProduct(
groupId: string, groupId: string,
opts?: { force?: false; page?: number; pageSize?: number }, opts?: { force?: false; page?: number; pageSize?: number },
@ -141,7 +145,12 @@ function toggleDeleteProduct(index: number) {
} }
function convertToTable(nodes: Node[]) { function convertToTable(nodes: Node[]) {
console.log(nodes); const _recursive = (v: Node): Node | Node[] => {
if (v.checked && v.children) return v.children.flatMap(_recursive);
if (v.checked) return v;
return [];
};
productServiceList.value = nodes.flatMap(_recursive).map((v) => v.value);
} }
function changeMode(mode: string) { function changeMode(mode: string) {
@ -343,7 +352,10 @@ onMounted(async () => {
</section> </section>
</template> </template>
<div class="surface-1 q-pa-md full-width"> <div class="surface-1 q-pa-md full-width">
<ProductItem @delete="toggleDeleteProduct" :rows="[]" /> <ProductItem
@delete="toggleDeleteProduct"
v-model:rows="productServiceList"
/>
</div> </div>
</q-expansion-item> </q-expansion-item>
@ -502,12 +514,7 @@ onMounted(async () => {
v-model:product-group="productGroup" v-model:product-group="productGroup"
v-model:product-list="productList" v-model:product-list="productList"
v-model:service-list="serviceList" v-model:service-list="serviceList"
@submit=" @submit="convertToTable"
(nodes) => {
convertToTable(nodes);
// pageState.productServiceModal = false;
}
"
@select-group=" @select-group="
async (id) => { async (id) => {
await getAllService(id); await getAllService(id);