refactor: quotation form & product service
This commit is contained in:
parent
8698268836
commit
c51f664beb
2 changed files with 90 additions and 92 deletions
|
|
@ -140,6 +140,7 @@ function mapCard() {
|
||||||
attributes: s.attributes,
|
attributes: s.attributes,
|
||||||
createAt: s.createdAt,
|
createAt: s.createdAt,
|
||||||
selectedImage: s.selectedImage,
|
selectedImage: s.selectedImage,
|
||||||
|
raw: s,
|
||||||
})) || [],
|
})) || [],
|
||||||
product:
|
product:
|
||||||
productList.value[selectedProductGroup.value]?.map((p) => ({
|
productList.value[selectedProductGroup.value]?.map((p) => ({
|
||||||
|
|
@ -154,6 +155,7 @@ function mapCard() {
|
||||||
serviceCharge: p.serviceCharge,
|
serviceCharge: p.serviceCharge,
|
||||||
process: p.process,
|
process: p.process,
|
||||||
selectedImage: p.selectedImage,
|
selectedImage: p.selectedImage,
|
||||||
|
raw: p,
|
||||||
})) || [],
|
})) || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -165,15 +167,12 @@ function mapNode() {
|
||||||
const node = selectedItems.value.map((v: Node) => {
|
const node = selectedItems.value.map((v: Node) => {
|
||||||
if (v.type === 'service') {
|
if (v.type === 'service') {
|
||||||
return {
|
return {
|
||||||
|
type: 'type',
|
||||||
id: v.id,
|
id: v.id,
|
||||||
title: v.name,
|
title: v.name,
|
||||||
subtitle: v.code,
|
subtitle: v.code,
|
||||||
detail: v.detail,
|
raw: v.raw,
|
||||||
attributes: {
|
|
||||||
additional: v.attributes.additional,
|
|
||||||
},
|
|
||||||
opened: v.work.length > 0,
|
opened: v.work.length > 0,
|
||||||
type: 'type',
|
|
||||||
icon: 'mdi-server-outline',
|
icon: 'mdi-server-outline',
|
||||||
bg: 'hsla(var(--orange-5-hsl)/0.1)',
|
bg: 'hsla(var(--orange-5-hsl)/0.1)',
|
||||||
fg: 'var(--orange-5)',
|
fg: 'var(--orange-5)',
|
||||||
|
|
@ -182,38 +181,30 @@ function mapNode() {
|
||||||
.filter((w: Work) => !w.name)
|
.filter((w: Work) => !w.name)
|
||||||
.flatMap((w: Work) =>
|
.flatMap((w: Work) =>
|
||||||
w.productOnWork.map((p) => ({
|
w.productOnWork.map((p) => ({
|
||||||
|
type: 'product',
|
||||||
id: p.product.id,
|
id: p.product.id,
|
||||||
title: p.product.name,
|
title: p.product.name,
|
||||||
subtitle: p.product.code || ' ',
|
subtitle: p.product.code || ' ',
|
||||||
detail: p.product.detail,
|
raw: p.product,
|
||||||
remark: p.product.remark,
|
|
||||||
price: p.product.price,
|
|
||||||
agentPrice: p.product.agentPrice,
|
|
||||||
serviceCharge: p.product.serviceCharge,
|
|
||||||
icon: 'mdi-shopping-outline',
|
icon: 'mdi-shopping-outline',
|
||||||
bg: 'hsla(var(--teal-10-hsl)/0.1)',
|
bg: 'hsla(var(--teal-10-hsl)/0.1)',
|
||||||
fg: 'var(--teal-10)',
|
fg: 'var(--teal-10)',
|
||||||
type: 'product',
|
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
const withNameObjects = v.work
|
const withNameObjects = v.work
|
||||||
.filter((w: Work) => w.name)
|
.filter((w: Work) => w.name)
|
||||||
.flatMap((w: Work) => ({
|
.flatMap((w: Work) => ({
|
||||||
|
type: 'work',
|
||||||
id: w.id,
|
id: w.id,
|
||||||
title: w.name,
|
title: w.name,
|
||||||
subtitle: ' ',
|
subtitle: ' ',
|
||||||
attributes: w.attributes,
|
raw: w,
|
||||||
type: 'work',
|
|
||||||
opened: w.productOnWork.length > 0,
|
opened: w.productOnWork.length > 0,
|
||||||
children: w.productOnWork.map((p) => ({
|
children: w.productOnWork.map((p) => ({
|
||||||
id: p.product.id,
|
id: p.product.id,
|
||||||
title: p.product.name,
|
title: p.product.name,
|
||||||
subtitle: p.product.code || ' ',
|
subtitle: p.product.code || ' ',
|
||||||
detail: p.product.detail,
|
raw: p.product,
|
||||||
remark: p.product.remark,
|
|
||||||
price: p.product.price,
|
|
||||||
agentPrice: p.product.agentPrice,
|
|
||||||
serviceCharge: p.product.serviceCharge,
|
|
||||||
type: 'product',
|
type: 'product',
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
@ -225,11 +216,7 @@ function mapNode() {
|
||||||
id: v.id,
|
id: v.id,
|
||||||
title: v.name,
|
title: v.name,
|
||||||
subtitle: v.code,
|
subtitle: v.code,
|
||||||
detail: v.detail,
|
raw: v.raw,
|
||||||
remark: v.remark,
|
|
||||||
price: v.price,
|
|
||||||
agentPrice: v.agentPrice,
|
|
||||||
serviceCharge: v.serviceCharge,
|
|
||||||
type: 'product',
|
type: 'product',
|
||||||
icon: 'mdi-shopping-outline',
|
icon: 'mdi-shopping-outline',
|
||||||
bg: 'hsla(var(--teal-10-hsl)/0.1)',
|
bg: 'hsla(var(--teal-10-hsl)/0.1)',
|
||||||
|
|
@ -525,7 +512,7 @@ watch(
|
||||||
<div
|
<div
|
||||||
class="row text-capitalize"
|
class="row text-capitalize"
|
||||||
:class="
|
:class="
|
||||||
pageState.infoTab === 'detail'
|
pageState.infoTab === '1'
|
||||||
? 'text-bold'
|
? 'text-bold'
|
||||||
: 'app-text-muted'
|
: 'app-text-muted'
|
||||||
"
|
"
|
||||||
|
|
@ -537,7 +524,7 @@ watch(
|
||||||
<div
|
<div
|
||||||
class="row text-capitalize"
|
class="row text-capitalize"
|
||||||
:class="
|
:class="
|
||||||
pageState.infoTab === 'remark'
|
pageState.infoTab === '2'
|
||||||
? 'text-bold'
|
? 'text-bold'
|
||||||
: 'app-text-muted'
|
: 'app-text-muted'
|
||||||
"
|
"
|
||||||
|
|
@ -568,7 +555,7 @@ watch(
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<aside class="surface-3 q-pa-md">
|
<aside class="surface-3 q-pa-md">
|
||||||
{{ selectedNode[0].detail || '-' }}
|
{{ selectedNode[0].raw.detail || '-' }}
|
||||||
</aside>
|
</aside>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
@ -593,16 +580,17 @@ watch(
|
||||||
"
|
"
|
||||||
class="surface-3 q-pa-md"
|
class="surface-3 q-pa-md"
|
||||||
>
|
>
|
||||||
{{ selectedNode[0].remark || '-' }}
|
{{ selectedNode[0].raw.remark || '-' }}
|
||||||
</aside>
|
</aside>
|
||||||
<aside v-else class="q-pt-md row q-gutter-sm">
|
<aside v-else class="q-pt-md row q-gutter-sm">
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
selectedNode[0].attributes.additional.length > 0
|
selectedNode[0].raw.attributes.additional
|
||||||
|
.length > 0
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="att in selectedNode[0].attributes
|
v-for="att in selectedNode[0].raw.attributes
|
||||||
.additional"
|
.additional"
|
||||||
:key="att"
|
:key="att"
|
||||||
class="bordered q-py-xs q-px-sm rounded"
|
class="bordered q-py-xs q-px-sm rounded"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { setLocale } from 'src/utils/datetime';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { QSelect, useQuasar } from 'quasar';
|
import { QSelect, useQuasar } from 'quasar';
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
import { setLocale } from 'src/utils/datetime';
|
||||||
|
import { dateFormat } from 'src/utils/datetime';
|
||||||
|
|
||||||
|
import useOptionStore from 'stores/options';
|
||||||
|
import { useQuotationForm } from './form';
|
||||||
|
import { Employee } from 'src/stores/employee/types';
|
||||||
|
import {
|
||||||
|
ProductGroup,
|
||||||
|
ProductList,
|
||||||
|
Service,
|
||||||
|
} from 'src/stores/product-service/types';
|
||||||
|
import { QuotationPayload } from 'src/stores/quotations/types';
|
||||||
|
|
||||||
import ProductServiceForm from './ProductServiceForm.vue';
|
import ProductServiceForm from './ProductServiceForm.vue';
|
||||||
import WorkerItem from 'components/05_quotation/WorkerItem.vue';
|
import WorkerItem from 'components/05_quotation/WorkerItem.vue';
|
||||||
|
|
@ -14,15 +27,6 @@ import DialogForm from 'src/components/DialogForm.vue';
|
||||||
import SelectZone from 'src/components/shared/SelectZone.vue';
|
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 { storeToRefs } from 'pinia';
|
|
||||||
import { useQuotationForm } from './form';
|
|
||||||
import { dateFormat } from 'src/utils/datetime';
|
|
||||||
import { Employee } from 'src/stores/employee/types';
|
|
||||||
import {
|
|
||||||
ProductGroup,
|
|
||||||
ProductList,
|
|
||||||
Service,
|
|
||||||
} from 'src/stores/product-service/types';
|
|
||||||
import useProductServiceStore from 'src/stores/product-service';
|
import useProductServiceStore from 'src/stores/product-service';
|
||||||
|
|
||||||
type Node = {
|
type Node = {
|
||||||
|
|
@ -39,6 +43,7 @@ defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const optionStore = useOptionStore();
|
||||||
const productServiceStore = useProductServiceStore();
|
const productServiceStore = useProductServiceStore();
|
||||||
const quotationForm = useQuotationForm();
|
const quotationForm = useQuotationForm();
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
|
|
@ -131,20 +136,12 @@ function triggerProductServiceDialog() {
|
||||||
// TODO: form and state controll
|
// TODO: form and state controll
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToTable(nodes: Node[]): Node[] {
|
function toggleDeleteProduct(index: number) {
|
||||||
const products: Node[] = [];
|
console.log(index);
|
||||||
|
}
|
||||||
|
|
||||||
nodes.forEach((node) => {
|
function convertToTable(nodes: Node[]) {
|
||||||
if (node.type === 'product' && node.checked) {
|
console.log(nodes);
|
||||||
products.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.children && node.children.length !== 0) {
|
|
||||||
products.push(...convertToTable(node.children)); // Correctly push the converted children
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return products;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeMode(mode: string) {
|
function changeMode(mode: string) {
|
||||||
|
|
@ -188,6 +185,11 @@ onMounted(async () => {
|
||||||
quotationFormData.value.customerBranchId =
|
quotationFormData.value.customerBranchId =
|
||||||
urlParams.get('customerBranchId') || '';
|
urlParams.get('customerBranchId') || '';
|
||||||
|
|
||||||
|
const resultOption = await fetch('/option/option.json');
|
||||||
|
const rawOption = await resultOption.json();
|
||||||
|
if (locale.value === 'eng') optionStore.globalOption = rawOption.eng;
|
||||||
|
if (locale.value === 'tha') optionStore.globalOption = rawOption.tha;
|
||||||
|
|
||||||
const getCurLang = localStorage.getItem('currentLanguage');
|
const getCurLang = localStorage.getItem('currentLanguage');
|
||||||
if (getCurLang === 'English') {
|
if (getCurLang === 'English') {
|
||||||
locale.value = 'eng';
|
locale.value = 'eng';
|
||||||
|
|
@ -270,23 +272,28 @@ onMounted(async () => {
|
||||||
header-class="surface-1"
|
header-class="surface-1"
|
||||||
>
|
>
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<div class="row full-width items-center q-pr-md q-py-sm">
|
<section class="row items-center full-width">
|
||||||
<span
|
<div class="row items-center q-pr-md q-py-sm">
|
||||||
class="text-weight-medium q-mr-md"
|
<span
|
||||||
style="font-size: 18px"
|
class="text-weight-medium q-mr-md"
|
||||||
>
|
style="font-size: 18px"
|
||||||
{{ $t('quotation.employeeList') }}
|
>
|
||||||
</span>
|
{{ $t('quotation.employeeList') }}
|
||||||
<ToggleButton class="q-mr-sm" v-model="toggleWorker" />
|
</span>
|
||||||
{{
|
<ToggleButton class="q-mr-sm" v-model="toggleWorker" />
|
||||||
toggleWorker ? $t('general.specify') : $t('general.noSpecify')
|
{{
|
||||||
}}
|
toggleWorker
|
||||||
</div>
|
? $t('general.specify')
|
||||||
<AddButton
|
: $t('general.noSpecify')
|
||||||
icon-only
|
}}
|
||||||
class="q-ml-auto"
|
</div>
|
||||||
@click.stop="triggerSelectEmployeeDialog"
|
<nav class="q-ml-auto">
|
||||||
/>
|
<AddButton
|
||||||
|
icon-only
|
||||||
|
@click.stop="triggerSelectEmployeeDialog"
|
||||||
|
/>
|
||||||
|
</nav>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="surface-1 q-pa-md full-width">
|
<div class="surface-1 q-pa-md full-width">
|
||||||
|
|
@ -320,27 +327,23 @@ onMounted(async () => {
|
||||||
header-class="surface-1"
|
header-class="surface-1"
|
||||||
>
|
>
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<div class="row full-width items-center q-pr-md q-py-sm">
|
<section class="row items-center full-width">
|
||||||
<span class="text-weight-medium" style="font-size: 18px">
|
<div class="row items-center q-pr-md q-py-sm">
|
||||||
{{ $t('quotation.productList') }}
|
<span class="text-weight-medium" style="font-size: 18px">
|
||||||
</span>
|
{{ $t('quotation.productList') }}
|
||||||
</div>
|
</span>
|
||||||
<AddButton
|
</div>
|
||||||
icon-only
|
<nav class="q-ml-auto">
|
||||||
class="q-ml-auto"
|
<AddButton
|
||||||
@click.stop="triggerProductServiceDialog"
|
icon-only
|
||||||
/>
|
class="q-ml-auto"
|
||||||
|
@click.stop="triggerProductServiceDialog"
|
||||||
|
/>
|
||||||
|
</nav>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<div class="surface-1 q-pa-md full-width">
|
<div class="surface-1 q-pa-md full-width">
|
||||||
<ProductItem
|
<ProductItem @delete="toggleDeleteProduct" :rows="[]" />
|
||||||
:rows="
|
|
||||||
rows.map((p) => ({
|
|
||||||
code: p.subtitle,
|
|
||||||
name: p.title,
|
|
||||||
}))
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
{{ console.log(rows) }}
|
|
||||||
</div>
|
</div>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
||||||
|
|
@ -358,7 +361,7 @@ onMounted(async () => {
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<div class="row full-width items-center q-pr-md q-py-sm">
|
<div class="row full-width items-center q-pr-md q-py-sm">
|
||||||
<span class="text-weight-medium" style="font-size: 18px">
|
<span class="text-weight-medium" style="font-size: 18px">
|
||||||
{{ $t('productService.group.title') }}
|
{{ $t('general.remark') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -501,8 +504,8 @@ onMounted(async () => {
|
||||||
v-model:service-list="serviceList"
|
v-model:service-list="serviceList"
|
||||||
@submit="
|
@submit="
|
||||||
(nodes) => {
|
(nodes) => {
|
||||||
rows = convertToTable(nodes);
|
convertToTable(nodes);
|
||||||
pageState.productServiceModal = false;
|
// pageState.productServiceModal = false;
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
@select-group="
|
@select-group="
|
||||||
|
|
@ -597,4 +600,11 @@ onMounted(async () => {
|
||||||
:deep(.q-editor__toolbar) {
|
:deep(.q-editor__toolbar) {
|
||||||
border-color: var(--surface-3) !important;
|
border-color: var(--surface-3) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(
|
||||||
|
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.surface-1
|
||||||
|
.q-focus-helper
|
||||||
|
) {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue