refactor: workerIndex
This commit is contained in:
parent
85b108a9b2
commit
7760f0f15a
4 changed files with 88 additions and 12 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { QTableProps } from 'quasar';
|
import { QTableProps } from 'quasar';
|
||||||
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';
|
||||||
|
|
||||||
|
|
@ -9,14 +8,12 @@ import WorkerItem from './WorkerItem.vue';
|
||||||
import DeleteButton from '../button/DeleteButton.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 { 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';
|
import { Product, Service, Work } from 'src/stores/product-service/types';
|
||||||
import { read } from 'fs';
|
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
agentPrice: boolean;
|
agentPrice: boolean;
|
||||||
employeeRows?: {
|
employeeRows?: {
|
||||||
|
|
@ -250,10 +247,22 @@ function groupByServiceId() {
|
||||||
groupList.value = groupedItems;
|
groupList.value = groupedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCheck(
|
||||||
|
index: number,
|
||||||
|
data: QuotationPayload['productServiceList'][number],
|
||||||
|
) {
|
||||||
|
const target = data.workerIndex.indexOf(index);
|
||||||
|
if (target > -1) {
|
||||||
|
data.workerIndex.splice(target, 1);
|
||||||
|
} else {
|
||||||
|
data.workerIndex.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => rows.value,
|
() => rows.value,
|
||||||
() => {
|
() => {
|
||||||
groupByServiceId();
|
if (rows.value.length > 0) groupByServiceId();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -263,6 +272,19 @@ watch(
|
||||||
summaryPrice.value = summary.value;
|
summaryPrice.value = summary.value;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.employeeRows,
|
||||||
|
(a, b) => {
|
||||||
|
if (a === undefined || b === undefined) return;
|
||||||
|
if (a.length < b.length) {
|
||||||
|
rows.value.forEach((p) => {
|
||||||
|
const maxValue = Math.max(...p.workerIndex);
|
||||||
|
p.workerIndex = p.workerIndex.filter((i) => i !== maxValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
|
@ -278,7 +300,7 @@ watch(
|
||||||
style="background: var(--orange-5); color: var(--surface-1)"
|
style="background: var(--orange-5); color: var(--surface-1)"
|
||||||
size="sm"
|
size="sm"
|
||||||
>
|
>
|
||||||
{{ i + 1 }}
|
<q-icon size="xs" name="mdi-server-outline" />
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -419,9 +441,12 @@ watch(
|
||||||
>
|
>
|
||||||
<q-td colspan="100%" style="padding: 16px">
|
<q-td colspan="100%" style="padding: 16px">
|
||||||
<WorkerItem
|
<WorkerItem
|
||||||
|
@check="(wokerIndex) => handleCheck(wokerIndex, props.row)"
|
||||||
|
checkable
|
||||||
fallback-img="/images/employee-avatar.png"
|
fallback-img="/images/employee-avatar.png"
|
||||||
inTable
|
inTable
|
||||||
hideQuantity
|
hideQuantity
|
||||||
|
:check-list="props.row.workerIndex"
|
||||||
:rows="employeeRows"
|
:rows="employeeRows"
|
||||||
/>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
<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 { onMounted } from 'vue';
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'delete', index: number): void;
|
(e: 'delete', index: number): void;
|
||||||
|
(e: 'check', index: number): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
withDefaults(
|
withDefaults(
|
||||||
|
|
@ -12,6 +14,7 @@ withDefaults(
|
||||||
employeeAmount?: number;
|
employeeAmount?: number;
|
||||||
fallbackImg?: string;
|
fallbackImg?: string;
|
||||||
hideQuantity?: boolean;
|
hideQuantity?: boolean;
|
||||||
|
checkable?: boolean;
|
||||||
inTable?: boolean;
|
inTable?: boolean;
|
||||||
rows: {
|
rows: {
|
||||||
foreignRefNo: string;
|
foreignRefNo: string;
|
||||||
|
|
@ -31,6 +34,8 @@ withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const checkList = defineModel<number[]>('checkList', { default: [] });
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
name: 'order',
|
name: 'order',
|
||||||
|
|
@ -87,13 +92,26 @@ const columns = [
|
||||||
<TableComponents
|
<TableComponents
|
||||||
flat
|
flat
|
||||||
bordered
|
bordered
|
||||||
button-delete
|
:button-delete="!checkable"
|
||||||
img-column="employeeName"
|
img-column="employeeName"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:inTable
|
:inTable
|
||||||
:columns
|
:columns="
|
||||||
|
checkable
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
name: 'check',
|
||||||
|
align: 'center',
|
||||||
|
label: '',
|
||||||
|
field: 'check',
|
||||||
|
},
|
||||||
|
...columns.filter((c) => c.name !== 'action'),
|
||||||
|
]
|
||||||
|
: columns
|
||||||
|
"
|
||||||
:rows
|
:rows
|
||||||
hidePagination
|
hidePagination
|
||||||
|
:customColumn="['check']"
|
||||||
@delete="(i) => $emit('delete', i)"
|
@delete="(i) => $emit('delete', i)"
|
||||||
>
|
>
|
||||||
<template v-slot:img-column="{ props }">
|
<template v-slot:img-column="{ props }">
|
||||||
|
|
@ -121,6 +139,20 @@ const columns = [
|
||||||
</div>
|
</div>
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body-cell-check="{ props }">
|
||||||
|
<q-td class="text-center">
|
||||||
|
<q-checkbox
|
||||||
|
size="xs"
|
||||||
|
@click.stop="
|
||||||
|
() => {
|
||||||
|
$emit('check', props.rowIndex);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:model-value="checkList.includes(props.rowIndex)"
|
||||||
|
></q-checkbox>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
</TableComponents>
|
</TableComponents>
|
||||||
|
|
||||||
<div v-if="!hideQuantity" class="row q-pt-md items-center">
|
<div v-if="!hideQuantity" class="row q-pt-md items-center">
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ function mapNode() {
|
||||||
detail: p.product.detail,
|
detail: p.product.detail,
|
||||||
remark: p.product.remark,
|
remark: p.product.remark,
|
||||||
value: {
|
value: {
|
||||||
|
workerIndex: [],
|
||||||
vat: 0,
|
vat: 0,
|
||||||
pricePerUnit,
|
pricePerUnit,
|
||||||
discount: 0,
|
discount: 0,
|
||||||
|
|
@ -258,6 +259,7 @@ function mapNode() {
|
||||||
subtitle: p.product.code || ' ',
|
subtitle: p.product.code || ' ',
|
||||||
checked: true,
|
checked: true,
|
||||||
value: {
|
value: {
|
||||||
|
workerIndex: [],
|
||||||
vat: 0,
|
vat: 0,
|
||||||
pricePerUnit,
|
pricePerUnit,
|
||||||
discount: 0,
|
discount: 0,
|
||||||
|
|
@ -282,6 +284,7 @@ function mapNode() {
|
||||||
title: v.name,
|
title: v.name,
|
||||||
subtitle: v.code,
|
subtitle: v.code,
|
||||||
value: {
|
value: {
|
||||||
|
workerIndex: [],
|
||||||
vat: 0,
|
vat: 0,
|
||||||
pricePerUnit,
|
pricePerUnit,
|
||||||
discount: 0,
|
discount: 0,
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,13 @@ import ToggleButton from 'components/button/ToggleButton.vue';
|
||||||
import FormAbout from 'components/05_quotation/FormAbout.vue';
|
import FormAbout from 'components/05_quotation/FormAbout.vue';
|
||||||
import SelectZone from 'components/shared/SelectZone.vue';
|
import SelectZone from 'components/shared/SelectZone.vue';
|
||||||
import PersonCard from 'components/shared/PersonCard.vue';
|
import PersonCard from 'components/shared/PersonCard.vue';
|
||||||
import { AddButton, SaveButton, EditButton } from 'components/button';
|
import {
|
||||||
|
AddButton,
|
||||||
|
SaveButton,
|
||||||
|
EditButton,
|
||||||
|
UndoButton,
|
||||||
|
DeleteButton,
|
||||||
|
} from 'components/button';
|
||||||
import ProductServiceForm from './ProductServiceForm.vue';
|
import ProductServiceForm from './ProductServiceForm.vue';
|
||||||
import QuotationFormInfo from './QuotationFormInfo.vue';
|
import QuotationFormInfo from './QuotationFormInfo.vue';
|
||||||
import ProfileBanner from 'components/ProfileBanner.vue';
|
import ProfileBanner from 'components/ProfileBanner.vue';
|
||||||
|
|
@ -250,7 +256,7 @@ async function assignToProductServiceList() {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
selectedProductGroup.value =
|
selectedProductGroup.value =
|
||||||
quotationFormData.value.productServiceList[0].product.productGroup?.id ||
|
quotationFormData.value.productServiceList[0]?.product.productGroup?.id ||
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -424,6 +430,9 @@ function convertToTable(nodes: Node[]) {
|
||||||
|
|
||||||
list.forEach((v) => {
|
list.forEach((v) => {
|
||||||
v.amount = Math.max(selectedWorker.value.length, 1);
|
v.amount = Math.max(selectedWorker.value.length, 1);
|
||||||
|
for (let i = 0; i < selectedWorker.value.length; i++) {
|
||||||
|
v.workerIndex.push(i);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
productServiceList.value = list;
|
productServiceList.value = list;
|
||||||
|
|
@ -437,6 +446,14 @@ function convertEmployeeToTable() {
|
||||||
v.amount + preSelectedWorker.value.length - selectedWorker.value.length,
|
v.amount + preSelectedWorker.value.length - selectedWorker.value.length,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
for (
|
||||||
|
let i = 0;
|
||||||
|
i < preSelectedWorker.value.length - selectedWorker.value.length;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
v.workerIndex.push(selectedWorker.value.length + i);
|
||||||
|
}
|
||||||
return v;
|
return v;
|
||||||
});
|
});
|
||||||
refSelectZoneEmployee.value?.assignSelect(
|
refSelectZoneEmployee.value?.assignSelect(
|
||||||
|
|
@ -715,7 +732,6 @@ watch(
|
||||||
productGroup.find((g) => g.id === selectedProductGroup)
|
productGroup.find((g) => g.id === selectedProductGroup)
|
||||||
?.name || '-'
|
?.name || '-'
|
||||||
}}
|
}}
|
||||||
<q-icon name="mdi-chevron-right" class="q-pl-sm" size="xs" />
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ProductItem
|
<ProductItem
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue