fix: product table
This commit is contained in:
parent
c2910ce459
commit
4e736a2c96
3 changed files with 326 additions and 122 deletions
|
|
@ -1,15 +1,17 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { QTableProps } from 'quasar';
|
import { QTableProps } from 'quasar';
|
||||||
import ThaiBahtText from 'thai-baht-text';
|
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 { 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';
|
||||||
import { QuotationPayload } from 'stores/quotations/types';
|
import { QuotationPayload } from 'stores/quotations/types';
|
||||||
import { formatNumberDecimal } from 'stores/utils';
|
import { formatNumberDecimal } from 'stores/utils';
|
||||||
import { useConfigStore } from 'stores/config';
|
import { useConfigStore } from 'stores/config';
|
||||||
|
import { Product, Service, Work } from 'src/stores/product-service/types';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
agentPrice: boolean;
|
agentPrice: boolean;
|
||||||
|
|
@ -27,6 +29,21 @@ const rows = defineModel<
|
||||||
Required<QuotationPayload['productServiceList'][number]>[]
|
Required<QuotationPayload['productServiceList'][number]>[]
|
||||||
>('rows', { required: true });
|
>('rows', { required: true });
|
||||||
|
|
||||||
|
const groupList = defineModel<
|
||||||
|
{
|
||||||
|
title: string;
|
||||||
|
product: {
|
||||||
|
amount: number;
|
||||||
|
discount: number;
|
||||||
|
pricePerUnit: number;
|
||||||
|
vat: number;
|
||||||
|
product: Product;
|
||||||
|
service?: Service;
|
||||||
|
work?: Work;
|
||||||
|
}[];
|
||||||
|
}[]
|
||||||
|
>('groupList', { default: [] });
|
||||||
|
|
||||||
const summaryPrice = defineModel<{
|
const summaryPrice = defineModel<{
|
||||||
totalPrice: number;
|
totalPrice: number;
|
||||||
totalDiscount: number;
|
totalDiscount: number;
|
||||||
|
|
@ -42,9 +59,13 @@ const summaryPrice = defineModel<{
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const totalDiscount4show = ref(summaryPrice.value.totalDiscount.toString());
|
||||||
|
|
||||||
function calcPrice(c: (typeof rows.value)[number]) {
|
function calcPrice(c: (typeof rows.value)[number]) {
|
||||||
return precisionRound(
|
return precisionRound(
|
||||||
c.pricePerUnit * c.amount - c.discount + c.vat * c.amount,
|
c.pricePerUnit * c.amount -
|
||||||
|
c.discount +
|
||||||
|
c.pricePerUnit * (config.value?.vat || 0.07) * c.amount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +108,7 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
align: 'left',
|
align: 'center',
|
||||||
label: 'productService.service.list',
|
label: 'productService.service.list',
|
||||||
field: (v) => v.product.name,
|
field: (v) => v.product.name,
|
||||||
},
|
},
|
||||||
|
|
@ -109,10 +130,16 @@ const columns = [
|
||||||
label: 'general.discount',
|
label: 'general.discount',
|
||||||
field: 'discount',
|
field: 'discount',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'priceBeforeVat',
|
||||||
|
align: 'center',
|
||||||
|
label: 'quotation.priceBeforeVat',
|
||||||
|
field: 'priceBeforeVat',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'tax',
|
name: 'tax',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
label: 'quotation.tax',
|
label: 'general.vat',
|
||||||
field: 'tax',
|
field: 'tax',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -144,13 +171,28 @@ watch(
|
||||||
<template>
|
<template>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="full-width">
|
<div class="full-width">
|
||||||
|
<section v-for="(item, i) in groupList" :key="i" class="q-pb-md">
|
||||||
|
<div
|
||||||
|
v-if="item.title"
|
||||||
|
class="q-py-sm q-px-md bordered"
|
||||||
|
style="background: hsla(var(--orange-5-hsl) / 0.1)"
|
||||||
|
>
|
||||||
|
<q-avatar
|
||||||
|
class="q-mr-lg"
|
||||||
|
style="background: var(--orange-5); color: var(--surface-1)"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
{{ i + 1 }}
|
||||||
|
</q-avatar>
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
<TableComponents
|
<TableComponents
|
||||||
flat
|
flat
|
||||||
bordered
|
bordered
|
||||||
hidePagination
|
hidePagination
|
||||||
button-delete
|
button-delete
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:rows="rows"
|
:rows="item.product"
|
||||||
:customColumn="[
|
:customColumn="[
|
||||||
'name',
|
'name',
|
||||||
'amount',
|
'amount',
|
||||||
|
|
@ -158,6 +200,7 @@ watch(
|
||||||
'discount',
|
'discount',
|
||||||
'tax',
|
'tax',
|
||||||
'sumPrice',
|
'sumPrice',
|
||||||
|
'priceBeforeVat',
|
||||||
]"
|
]"
|
||||||
@delete="(i) => $emit('delete', i)"
|
@delete="(i) => $emit('delete', i)"
|
||||||
>
|
>
|
||||||
|
|
@ -189,7 +232,13 @@ watch(
|
||||||
|
|
||||||
<template v-slot:body-cell-pricePerUnit="{ props }">
|
<template v-slot:body-cell-pricePerUnit="{ props }">
|
||||||
<q-td align="right">
|
<q-td align="right">
|
||||||
{{ formatNumberDecimal(props.row.pricePerUnit, 2) }}
|
{{
|
||||||
|
formatNumberDecimal(
|
||||||
|
props.row.pricePerUnit +
|
||||||
|
props.row.pricePerUnit * (config?.vat || 0.07),
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
}}
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -199,15 +248,22 @@ watch(
|
||||||
dense
|
dense
|
||||||
min="0"
|
min="0"
|
||||||
outlined
|
outlined
|
||||||
|
input-class="text-right"
|
||||||
type="number"
|
type="number"
|
||||||
style="width: 70px"
|
style="width: 90px"
|
||||||
v-model="props.row.discount"
|
v-model="props.row.discount"
|
||||||
/>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body-cell-priceBeforeVat="{ props }">
|
||||||
|
<q-td align="right">
|
||||||
|
{{ formatNumberDecimal(props.row.pricePerUnit, 2) }}
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-slot:body-cell-tax="{ props }">
|
<template v-slot:body-cell-tax="{ props }">
|
||||||
<q-td align="center">
|
<q-td align="right">
|
||||||
{{
|
{{
|
||||||
precisionRound(
|
precisionRound(
|
||||||
(props.row.pricePerUnit * props.row.amount -
|
(props.row.pricePerUnit * props.row.amount -
|
||||||
|
|
@ -239,10 +295,93 @@ watch(
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</TableComponents>
|
</TableComponents>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row text-weight-bold text-caption items-start">
|
||||||
|
<span
|
||||||
|
class="col row items-center justify-between q-px-md q-py-xs q-mr-lg rounded bg-color-orange-light"
|
||||||
|
>
|
||||||
|
<span class="app-text-muted-2">
|
||||||
|
{{ $t('general.totalAmount') }}
|
||||||
|
</span>
|
||||||
|
<span v-if="summary.finalPrice">
|
||||||
|
{{
|
||||||
|
$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.totalPrice, 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') }}
|
||||||
|
{{ console.log(totalDiscount4show) }}
|
||||||
|
</span>
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
class="col price-tag"
|
||||||
|
outlined
|
||||||
|
input-class="text-right text-bold"
|
||||||
|
v-model="summary.totalDiscount"
|
||||||
|
/>
|
||||||
|
<!-- <q-input
|
||||||
|
dense
|
||||||
|
class="col price-tag"
|
||||||
|
outlined
|
||||||
|
input-class="text-right text-bold"
|
||||||
|
:model-value="commaInput(summary.totalDiscount.toString())"
|
||||||
|
@update:model-value="
|
||||||
|
(v) => {
|
||||||
|
if (typeof v === 'string') totalDiscount4show = commaInput(v);
|
||||||
|
const x = parseInt(
|
||||||
|
totalDiscount4show && typeof totalDiscount4show === 'string'
|
||||||
|
? totalDiscount4show.replace(/,/g, '')
|
||||||
|
: '',
|
||||||
|
);
|
||||||
|
summary.totalDiscount = x;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="column q-ml-auto text-caption app-text-muted-2 q-pt-md"
|
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(summary.finalPrice, 2)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div
|
||||||
|
class="column q-ml-auto text-caption app-text-muted-2"
|
||||||
style="width: 15vw"
|
style="width: 15vw"
|
||||||
>
|
>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
@ -280,11 +419,26 @@ watch(
|
||||||
? EngBahtText(summary.finalPrice)
|
? EngBahtText(summary.finalPrice)
|
||||||
: ThaiBahtText(summary.finalPrice)
|
: ThaiBahtText(summary.finalPrice)
|
||||||
}})
|
}})
|
||||||
</span>
|
</span> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.bg-color-orange-light {
|
||||||
|
--_color: var(--yellow-7-hsl);
|
||||||
|
background: hsla(var(--_color) / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-color-orange {
|
||||||
|
--_color: var(--yellow-7-hsl);
|
||||||
|
color: white;
|
||||||
|
background: hsla(var(--_color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .bg-color-orange {
|
||||||
|
--_color: var(--orange-6-hsl / 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.worker-item {
|
.worker-item {
|
||||||
--side-color: var(--brand-1);
|
--side-color: var(--brand-1);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -299,6 +453,12 @@ watch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.price-tag .q-field__control) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
.worker-item::before {
|
.worker-item::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: ' ';
|
content: ' ';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, reactive, ref, watch } from 'vue';
|
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
||||||
import { moveItemUp, moveItemDown, deleteItem } from 'stores/utils';
|
import { moveItemUp, moveItemDown, deleteItem } from 'stores/utils';
|
||||||
import useOptionStore from 'stores/options';
|
import useOptionStore from 'stores/options';
|
||||||
|
|
||||||
|
|
@ -46,6 +46,9 @@ const emit = defineEmits<{
|
||||||
(e: 'submit', nodes: Node[]): void;
|
(e: 'submit', nodes: Node[]): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const selectedProductGroup = defineModel<string>('selectedProductGroup', {
|
||||||
|
default: '',
|
||||||
|
});
|
||||||
const model = defineModel<boolean>();
|
const model = defineModel<boolean>();
|
||||||
const inputSearch = defineModel<string>('inputSearch');
|
const inputSearch = defineModel<string>('inputSearch');
|
||||||
const productGroup = defineModel<ProductGroup[]>('productGroup', {
|
const productGroup = defineModel<ProductGroup[]>('productGroup', {
|
||||||
|
|
@ -90,7 +93,6 @@ const productServiceCard = ref<{
|
||||||
const splitterModel = ref(0);
|
const splitterModel = ref(0);
|
||||||
const selectedType = ref<'group' | 'type' | 'work' | 'product' | ''>('');
|
const selectedType = ref<'group' | 'type' | 'work' | 'product' | ''>('');
|
||||||
const selectedNode = ref<Node[]>([]);
|
const selectedNode = ref<Node[]>([]);
|
||||||
const selectedProductGroup = ref('');
|
|
||||||
const selectedItems = ref<Record<string, any>[]>([]);
|
const selectedItems = ref<Record<string, any>[]>([]);
|
||||||
const preSelectedItems = ref<Record<string, any>[]>([]);
|
const preSelectedItems = ref<Record<string, any>[]>([]);
|
||||||
const refSelectZone = ref<InstanceType<typeof SelectZone>>();
|
const refSelectZone = ref<InstanceType<typeof SelectZone>>();
|
||||||
|
|
@ -106,9 +108,13 @@ function triggerInfo() {
|
||||||
pageState.infoDrawer = !pageState.infoDrawer;
|
pageState.infoDrawer = !pageState.infoDrawer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerAddDialog() {
|
async function triggerAddDialog() {
|
||||||
assignSelect(preSelectedItems.value, selectedItems.value);
|
|
||||||
pageState.addModal = true;
|
pageState.addModal = true;
|
||||||
|
await nextTick();
|
||||||
|
refSelectZone.value?.assignSelect(
|
||||||
|
preSelectedItems.value,
|
||||||
|
selectedItems.value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSelected(node: Node) {
|
function toggleSelected(node: Node) {
|
||||||
|
|
@ -179,7 +185,10 @@ function mapCard() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapNode() {
|
function mapNode() {
|
||||||
assignSelect(selectedItems.value, preSelectedItems.value);
|
refSelectZone.value?.assignSelect(
|
||||||
|
selectedItems.value,
|
||||||
|
preSelectedItems.value,
|
||||||
|
);
|
||||||
|
|
||||||
const node = selectedItems.value.map((v) => {
|
const node = selectedItems.value.map((v) => {
|
||||||
if (v.type === 'service') {
|
if (v.type === 'service') {
|
||||||
|
|
@ -261,11 +270,11 @@ function mapNode() {
|
||||||
})(),
|
})(),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const price = prop.agentPrice ? v.agentPrice : v.price;
|
const price = prop.agentPrice ? v.raw.agentPrice : v.raw.price;
|
||||||
const pricePerUnit = v.vatIncluded
|
const pricePerUnit = v.raw.vatIncluded
|
||||||
? precisionRound(price / (1 + (config.value?.vat || 0.07)))
|
? precisionRound(price / (1 + (config.value?.vat || 0.07)))
|
||||||
: price;
|
: price;
|
||||||
|
console.log(v);
|
||||||
return {
|
return {
|
||||||
id: v.id,
|
id: v.id,
|
||||||
title: v.name,
|
title: v.name,
|
||||||
|
|
@ -292,19 +301,6 @@ function mapNode() {
|
||||||
pageState.addModal = false;
|
pageState.addModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignSelect(to: Record<string, any>[], from: Record<string, any>[]) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => selectedNode.value,
|
() => selectedNode.value,
|
||||||
(v) => {
|
(v) => {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import {
|
||||||
ProductGroup,
|
ProductGroup,
|
||||||
Product,
|
Product,
|
||||||
Service,
|
Service,
|
||||||
|
Work,
|
||||||
} from 'src/stores/product-service/types';
|
} from 'src/stores/product-service/types';
|
||||||
|
|
||||||
// NOTE: Import Components
|
// NOTE: Import Components
|
||||||
|
|
@ -109,6 +110,7 @@ const selectedWorker = ref<
|
||||||
>([]);
|
>([]);
|
||||||
const workerList = ref<Employee[]>([]);
|
const workerList = ref<Employee[]>([]);
|
||||||
|
|
||||||
|
const selectedProductGroup = ref('');
|
||||||
const agentPrice = ref(false);
|
const agentPrice = ref(false);
|
||||||
const summaryPrice = ref<{
|
const summaryPrice = ref<{
|
||||||
totalPrice: number;
|
totalPrice: number;
|
||||||
|
|
@ -184,6 +186,20 @@ const formDataEmployee = ref<
|
||||||
const productServiceList = ref<
|
const productServiceList = ref<
|
||||||
Required<QuotationPayload['productServiceList'][number]>[]
|
Required<QuotationPayload['productServiceList'][number]>[]
|
||||||
>([]);
|
>([]);
|
||||||
|
const productServiceTableData = ref<
|
||||||
|
{
|
||||||
|
title: string;
|
||||||
|
product: {
|
||||||
|
amount: number;
|
||||||
|
discount: number;
|
||||||
|
pricePerUnit: number;
|
||||||
|
vat: number;
|
||||||
|
product: Product;
|
||||||
|
service?: Service;
|
||||||
|
work?: Work;
|
||||||
|
}[];
|
||||||
|
}[]
|
||||||
|
>([{ title: '', product: [] }]);
|
||||||
|
|
||||||
function convertDataToFormSubmit() {
|
function convertDataToFormSubmit() {
|
||||||
quotationFormData.value.productServiceList = JSON.parse(
|
quotationFormData.value.productServiceList = JSON.parse(
|
||||||
|
|
@ -318,6 +334,25 @@ function convertToTable(nodes: Node[]) {
|
||||||
|
|
||||||
productServiceList.value = list;
|
productServiceList.value = list;
|
||||||
|
|
||||||
|
const pdList: Node[] = [];
|
||||||
|
const groupByService = nodes
|
||||||
|
.map((n) => {
|
||||||
|
if (n.type === 'type' && n.children) {
|
||||||
|
const products = n.children.flatMap(_recursive).map((v) => v.value);
|
||||||
|
return {
|
||||||
|
title: n.title,
|
||||||
|
product: products,
|
||||||
|
};
|
||||||
|
} else if (n.type === 'product') {
|
||||||
|
pdList.push(n.value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter((t) => t !== null);
|
||||||
|
if (pdList.length > 0) groupByService.push({ title: '', product: pdList });
|
||||||
|
productServiceTableData.value = [];
|
||||||
|
productServiceTableData.value = groupByService;
|
||||||
|
|
||||||
pageState.productServiceModal = false;
|
pageState.productServiceModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,9 +625,21 @@ watch(
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<div class="surface-1 q-pa-md full-width">
|
<div class="surface-1 q-pa-md full-width">
|
||||||
|
<span
|
||||||
|
v-if="productServiceList.length > 0"
|
||||||
|
class="text-weight-bold row items-center q-pb-md"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
productGroup.find((g) => g.id === selectedProductGroup)
|
||||||
|
?.name || '-'
|
||||||
|
}}
|
||||||
|
<q-icon name="mdi-chevron-right" class="q-pl-sm" size="xs" />
|
||||||
|
</span>
|
||||||
|
|
||||||
<ProductItem
|
<ProductItem
|
||||||
:agent-price="agentPrice"
|
:agent-price="agentPrice"
|
||||||
@delete="toggleDeleteProduct"
|
@delete="toggleDeleteProduct"
|
||||||
|
v-model:groupList="productServiceTableData"
|
||||||
v-model:rows="productServiceList"
|
v-model:rows="productServiceList"
|
||||||
v-model:summary-price="summaryPrice"
|
v-model:summary-price="summaryPrice"
|
||||||
/>
|
/>
|
||||||
|
|
@ -791,6 +838,7 @@ watch(
|
||||||
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"
|
||||||
|
v-model:selected-product-group="selectedProductGroup"
|
||||||
:agent-price="agentPrice"
|
:agent-price="agentPrice"
|
||||||
@submit="convertToTable"
|
@submit="convertToTable"
|
||||||
@select-group="
|
@select-group="
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue