refactor: handle mode view

This commit is contained in:
Thanaphon Frappet 2025-02-24 15:23:49 +07:00
parent be69f66742
commit 83a7e7ee47
3 changed files with 104 additions and 57 deletions

View file

@ -7,6 +7,7 @@ import { dateFormatJS, calculateAge } from 'src/utils/datetime';
import { initLang, initTheme, Lang } from 'src/utils/ui';
import { useQuotationStore } from 'src/stores/quotations';
import { useQuotationForm } from 'src/pages/05_quotation/form';
import { useDebitNoteForm } from './form';
import { useReceipt, usePayment } from 'stores/payment';
import useProductServiceStore from 'stores/product-service';
import {
@ -63,6 +64,7 @@ import { precisionRound } from 'src/utils/arithmetic';
import QuotationFormProductSelect from '../05_quotation/QuotationFormProductSelect.vue';
import { getName } from 'src/services/keycloak';
const debitNoteForm = useDebitNoteForm();
const route = useRoute();
const router = useRouter();
const debitNote = useDebitNote();
@ -76,6 +78,7 @@ const $q = useQuasar();
const paymentStore = usePayment();
const { data: config } = storeToRefs(configStore);
const { newWorkerList } = storeToRefs(quotationForm);
const { currentFormData } = storeToRefs(debitNoteForm);
const { t, locale } = useI18n();
const requestStore = useRequestList();
@ -104,6 +107,7 @@ const quotationData = ref<DebitNote['debitNoteQuotation']>();
const view = ref<QuotationStatus>(QuotationStatus.Issued);
const fileList = ref<FileList>();
const receiptList = ref<Receipt[]>([]);
let previousValue: DebitNotePayload | undefined = undefined;
const rowsRequestList = ref<RequestData[]>([]);
@ -111,20 +115,7 @@ const productServiceList = ref<
Required<QuotationPayload['productServiceList'][number]>[]
>([]);
const productServiceNodes = ref<ProductTree>([]);
const currentFormData = ref<DebitNotePayload>({
productServiceList: [],
debitNoteQuotationId: '',
worker: [],
payBillDate: new Date(),
paySplitCount: 0,
payCondition: PayCondition.Full,
dueDate: new Date(Date.now() + 86400000),
discount: 0,
status: 'CREATED',
remark: '#[quotation-labor]<br/><br/>#[quotation-payment]',
quotationId: '',
agentPrice: false,
});
const tempPaySplitCount = ref(0);
const tempPaySplit = ref<
{ no: number; amount: number; name?: string; invoice?: boolean }[]
@ -335,6 +326,46 @@ async function assignToProductServiceList() {
}
}
function undo() {
if (!previousValue) return;
currentFormData.value = structuredClone(previousValue);
assignProductServiceList();
assignSelectedWorker();
pageState.mode = 'info';
}
function assignProductServiceList() {
if (!debitNoteData.value) return;
productServiceList.value = debitNoteData.value.productServiceList.map(
(v, i) => ({
id: v.id!,
installmentNo: v.installmentNo || 0,
workerIndex: v.worker
.map((a) =>
debitNoteData.value!.worker.findIndex(
(b) => b.employeeId === a.employeeId,
),
)
.filter(
(index): index is number => index !== -1 && index !== undefined,
),
vat: v.vat || 0,
pricePerUnit: v.pricePerUnit || 0,
discount: v.discount || 0,
amount: v.amount || 0,
product: v.product,
work: v.work || null,
service: v.service || null,
}),
);
}
function assignSelectedWorker() {
if (debitNoteData.value)
selectedWorker.value = debitNoteData.value.worker.map((v) => v.employee);
}
async function assignFormData(id: string) {
const data = await debitNote.getDebitNote(id);
if (!data) return;
@ -344,7 +375,7 @@ async function assignFormData(id: string) {
selectedProductGroup.value =
data.productServiceList[0]?.product.productGroup?.id || '';
currentFormData.value = {
(previousValue = {
id: data.id || undefined,
debitNoteQuotationId: data.debitNoteQuotationId || undefined,
productServiceList: structuredClone(
@ -369,24 +400,11 @@ async function assignFormData(id: string) {
agentPrice: data.agentPrice,
quotationId: data.debitNoteQuotationId,
remark: data.remark || undefined,
};
}),
(currentFormData.value = structuredClone(previousValue));
productServiceList.value = data.productServiceList.map((v, i) => ({
id: v.id!,
installmentNo: v.installmentNo || 0,
workerIndex: v.worker.map((a) =>
data.worker.findIndex((b) => b.employeeId === a.employeeId),
) || [0],
vat: v.vat || 0,
pricePerUnit: v.pricePerUnit || 0,
discount: v.discount || 0,
amount: v.amount || 0,
product: v.product,
work: v.work || null,
service: v.service || null,
}));
selectedWorker.value = data.worker.map((v) => v.employee);
assignProductServiceList();
assignSelectedWorker();
await getQuotation(data.debitNoteQuotation?.id);
await assignToProductServiceList();
await fetchRequest();
@ -431,7 +449,10 @@ async function initStatus() {
title: 'title',
status: debitNoteData.value?.id !== undefined ? 'done' : 'doing',
active: () => view.value === QuotationStatus.Issued,
handler: () => (view.value = QuotationStatus.Issued),
handler: () => {
pageState.mode = 'info';
view.value = QuotationStatus.Issued;
},
},
{
title: 'accepted',
@ -440,7 +461,10 @@ async function initStatus() {
? getStatus(debitNoteData.value.quotationStatus, 1, -1)
: 'waiting',
active: () => view.value === QuotationStatus.Accepted,
handler: () => (view.value = QuotationStatus.Accepted),
handler: () => {
pageState.mode = 'info';
view.value = QuotationStatus.Accepted;
},
},
{
title: 'payment',
@ -459,6 +483,7 @@ async function initStatus() {
status: getStatus(debitNoteData.value?.quotationStatus, 2, 2),
active: () => view.value === QuotationStatus.PaymentSuccess,
handler: () => {
pageState.mode = 'info';
view.value = QuotationStatus.PaymentSuccess;
},
},
@ -468,6 +493,7 @@ async function initStatus() {
status: getStatus(debitNoteData.value?.quotationStatus, 3, 2),
active: () => view.value === QuotationStatus.ProcessComplete,
handler: () => {
pageState.mode = 'info';
view.value = QuotationStatus.ProcessComplete;
},
},
@ -906,6 +932,12 @@ onMounted(async () => {
}[route.query['tab']] || QuotationStatus.Issued;
}
if (
pageState.mode === 'edit' &&
debitNoteData.value?.quotationStatus !== QuotationStatus.Issued
) {
pageState.mode = 'info';
}
await useConfigStore().getConfig();
});
@ -1236,10 +1268,13 @@ async function submitAccepted() {
</MainButton>
<div class="row q-gutter-x-sm">
<UndoButton outlined @click="pageState.mode = 'info'" v-if="false" />
{{ pageState.mode }}
<UndoButton
outlined
v-if="pageState.mode === 'edit'"
@click="undo()"
/>
<SaveButton
v-if="!readonly"
v-if="pageState.mode !== 'info'"
:disabled="
selectedWorkerItem.length === 0 && productService.length === 0
"
@ -1247,24 +1282,36 @@ async function submitAccepted() {
solid
/>
<SaveButton
v-if="false"
@click="submit"
:label="$t('debitNote.label.submit')"
icon="mdi-account-multiple-check-outline"
solid
/>
<template v-if="debitNoteData">
<EditButton
v-if="
pageState.mode === 'info' &&
view === QuotationStatus.Issued &&
debitNoteData.quotationStatus === QuotationStatus.Issued
"
class="no-print"
solid
@click="pageState.mode = 'edit'"
/>
<EditButton
v-if="
readonly &&
pageState.mode === 'info' &&
QuotationStatus.Issued === view
"
class="no-print"
solid
@click="pageState.mode = 'edit'"
/>
<MainButton
v-if="
view === QuotationStatus.Accepted &&
debitNoteData.quotationStatus === QuotationStatus.Issued
"
solid
icon="mdi-account-multiple-check-outline"
color="207 96% 32%"
id="btn-submit-accepted"
@click="
() => {
submitAccepted();
}
"
>
{{ $t('quotation.customerAcceptance') }}
</MainButton>
</template>
</div>
</nav>
</footer>

View file

@ -54,7 +54,7 @@ const toggleWorker = defineModel<boolean>('toggleWorker');
</div>
<nav class="q-ml-auto">
<AddButton
v-if="!hideBtnAddWorker"
v-if="!readonly"
icon-only
@click.stop="$emit('addWorker')"
/>

View file

@ -14,10 +14,9 @@ const DEFAULT_DATA: DebitNotePayload = {
debitNoteQuotationId: '',
worker: [],
payBillDate: new Date(),
paySplit: [],
paySplitCount: 0,
payCondition: PayCondition.Full,
dueDate: new Date(),
dueDate: new Date(Date.now() + 86400000),
discount: 0,
status: 'CREATED',
remark: '#[quotation-labor]<br/><br/>#[quotation-payment]',
@ -58,6 +57,7 @@ export const useDebitNoteForm = defineStore('form-debit-note', () => {
}
return {
currentFormData,
isFormDataDifferent,
resetForm,
};