refactor: receiptDialog
This commit is contained in:
parent
fddc0341c5
commit
200cce9e7e
1 changed files with 157 additions and 17 deletions
|
|
@ -6,27 +6,49 @@ import { formatNumberDecimal } from 'stores/utils';
|
||||||
import DialogForm from 'src/components/DialogForm.vue';
|
import DialogForm from 'src/components/DialogForm.vue';
|
||||||
import { reactive, ref, watch } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import { useQuotationPayment } from 'src/stores/quotations';
|
import { useQuotationPayment } from 'src/stores/quotations';
|
||||||
import { Quotation, QuotationPaymentData } from 'src/stores/quotations/types';
|
import {
|
||||||
|
PaymentPayload,
|
||||||
|
Quotation,
|
||||||
|
QuotationPaymentData,
|
||||||
|
} from 'src/stores/quotations/types';
|
||||||
import { dateFormat } from 'src/utils/datetime';
|
import { dateFormat } from 'src/utils/datetime';
|
||||||
import { QFile } from 'quasar';
|
import { QFile, QMenu } from 'quasar';
|
||||||
import UploadFileCard from 'src/components/upload-file/UploadFileCard.vue';
|
import UploadFileCard from 'src/components/upload-file/UploadFileCard.vue';
|
||||||
|
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
const quotationPayment = useQuotationPayment();
|
const quotationPayment = useQuotationPayment();
|
||||||
const { data: config } = storeToRefs(configStore);
|
const { data: config } = storeToRefs(configStore);
|
||||||
|
|
||||||
defineEmits<{
|
|
||||||
(e: 'upload', index: number): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const model = defineModel<boolean>({ default: false, required: true });
|
const model = defineModel<boolean>({ default: false, required: true });
|
||||||
const data = defineModel<Quotation | undefined>('data', { required: true });
|
const data = defineModel<Quotation | undefined>('data', { required: true });
|
||||||
|
|
||||||
const fileManager =
|
const fileManager =
|
||||||
ref<ReturnType<typeof quotationPayment.createPaymentFileManager>>();
|
ref<ReturnType<typeof quotationPayment.createPaymentFileManager>>();
|
||||||
const refQFile = ref<InstanceType<typeof QFile>[]>([]);
|
const refQFile = ref<InstanceType<typeof QFile>[]>([]);
|
||||||
|
const refQMenu = ref<InstanceType<typeof QMenu>[]>([]);
|
||||||
const paymentData = ref<QuotationPaymentData[]>([]);
|
const paymentData = ref<QuotationPaymentData[]>([]);
|
||||||
|
const submitPaymentData = ref<QuotationPaymentData[]>([]);
|
||||||
const payAll = ref<boolean>(false);
|
const payAll = ref<boolean>(false);
|
||||||
|
const paymentStatusOpts = [
|
||||||
|
{
|
||||||
|
status: 'PaymentInProcess',
|
||||||
|
icon: 'mdi-credit-card-clock-outline',
|
||||||
|
color: 'danger',
|
||||||
|
name: 'quotation.receiptDialog.PaymentInProcess',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 'PaymentRetry',
|
||||||
|
icon: 'mdi-information-outline',
|
||||||
|
color: 'negative',
|
||||||
|
name: 'quotation.receiptDialog.PaymentRetry',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 'PaymentSuccess',
|
||||||
|
icon: 'mdi-check-decagram-outline',
|
||||||
|
color: 'positive',
|
||||||
|
name: 'quotation.receiptDialog.PaymentSuccess',
|
||||||
|
},
|
||||||
|
];
|
||||||
const slipFile = ref<
|
const slipFile = ref<
|
||||||
{
|
{
|
||||||
quotationId: string;
|
quotationId: string;
|
||||||
|
|
@ -119,12 +141,46 @@ async function triggerDelete(
|
||||||
await getSlipList(payment, index);
|
await getSlipList(payment, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function triggerViewSlip(payment: QuotationPaymentData, name: string) {
|
function triggerViewSlip(payment: QuotationPaymentData, name: string) {
|
||||||
if (!data.value || !fileManager.value) return;
|
if (!data.value || !fileManager.value) return;
|
||||||
const url = `${baseUrl}/quotation/${data.value.id}/payment/${payment.id}/attachment/${name}`;
|
const url = `${baseUrl}/quotation/${data.value.id}/payment/${payment.id}/attachment/${name}`;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectStatus(
|
||||||
|
payment: QuotationPaymentData,
|
||||||
|
status: string,
|
||||||
|
index: number,
|
||||||
|
) {
|
||||||
|
const existingPayment = submitPaymentData.value.findIndex(
|
||||||
|
(p: QuotationPaymentData) => p.id === payment.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingPayment !== -1) {
|
||||||
|
submitPaymentData.value[existingPayment].paymentStatus = status;
|
||||||
|
} else {
|
||||||
|
payment.paymentStatus = status;
|
||||||
|
submitPaymentData.value.push(payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
refQMenu.value[index].hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function triggerSubmit() {
|
||||||
|
submitPaymentData.value.forEach(async (p) => {
|
||||||
|
if (!data.value) return;
|
||||||
|
|
||||||
|
const payload: PaymentPayload = {
|
||||||
|
paymentStatus: p.paymentStatus,
|
||||||
|
remark: p.remark || '',
|
||||||
|
date: new Date(p.date),
|
||||||
|
amount: p.amount,
|
||||||
|
};
|
||||||
|
await quotationPayment.updateQuotationPayment(data.value.id, p.id, payload);
|
||||||
|
});
|
||||||
|
model.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => model.value,
|
() => model.value,
|
||||||
async (open) => {
|
async (open) => {
|
||||||
|
|
@ -133,6 +189,7 @@ watch(
|
||||||
paymentData.value = [];
|
paymentData.value = [];
|
||||||
state.payExpansion = [];
|
state.payExpansion = [];
|
||||||
slipFile.value = [];
|
slipFile.value = [];
|
||||||
|
submitPaymentData.value = [];
|
||||||
} else {
|
} else {
|
||||||
fileManager.value = quotationPayment.createPaymentFileManager(
|
fileManager.value = quotationPayment.createPaymentFileManager(
|
||||||
data.value.id,
|
data.value.id,
|
||||||
|
|
@ -155,7 +212,7 @@ watch(
|
||||||
:title="$t('quotation.receipt')"
|
:title="$t('quotation.receipt')"
|
||||||
v-model:modal="model"
|
v-model:modal="model"
|
||||||
width="65%"
|
width="65%"
|
||||||
hideFooter
|
:submit="() => triggerSubmit()"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="data"
|
v-if="data"
|
||||||
|
|
@ -343,7 +400,7 @@ watch(
|
||||||
<span class="bordered rounded surface-2 number-box q-mx-sm">
|
<span class="bordered rounded surface-2 number-box q-mx-sm">
|
||||||
{{
|
{{
|
||||||
paymentData.reduce(
|
paymentData.reduce(
|
||||||
(c, i) => (i.paymentStatus === 'PaymentWait' ? c + 1 : c),
|
(c, i) => (i.paymentStatus !== 'PaymentSuccess' ? c + 1 : c),
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -396,7 +453,9 @@ watch(
|
||||||
? formatNumberDecimal(
|
? formatNumberDecimal(
|
||||||
paymentData.reduce(
|
paymentData.reduce(
|
||||||
(c, i) =>
|
(c, i) =>
|
||||||
i.paymentStatus === 'PaymentWait' ? c + i.amount : c,
|
i.paymentStatus !== 'PaymentSuccess'
|
||||||
|
? c + i.amount
|
||||||
|
: c,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
2,
|
2,
|
||||||
|
|
@ -457,7 +516,7 @@ watch(
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<!-- <div
|
||||||
class="q-ml-auto items-center flex q-py-xs q-px-sm rounded"
|
class="q-ml-auto items-center flex q-py-xs q-px-sm rounded"
|
||||||
:class="{
|
:class="{
|
||||||
'payment-success': p.paymentStatus === 'PaymentSuccess',
|
'payment-success': p.paymentStatus === 'PaymentSuccess',
|
||||||
|
|
@ -473,7 +532,70 @@ watch(
|
||||||
? $t('quotation.receiptDialog.notYetPaid')
|
? $t('quotation.receiptDialog.notYetPaid')
|
||||||
: $t('quotation.receiptDialog.alreadyPaid')
|
: $t('quotation.receiptDialog.alreadyPaid')
|
||||||
}}
|
}}
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
@click.stop
|
||||||
|
unelevated
|
||||||
|
padding="4px 8px"
|
||||||
|
class="q-ml-auto rounded text-capitalize text-weight-regular payment-wait row items-center"
|
||||||
|
:class="{
|
||||||
|
'payment-pending': p.paymentStatus === 'PaymentWait',
|
||||||
|
'payment-process':
|
||||||
|
p.paymentStatus === 'PaymentInProcess',
|
||||||
|
'payment-retry': p.paymentStatus === 'PaymentRetry',
|
||||||
|
'payment-success': p.paymentStatus === 'PaymentSuccess',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
size="xs"
|
||||||
|
:name="
|
||||||
|
paymentStatusOpts.find(
|
||||||
|
(s) => s.status === p.paymentStatus,
|
||||||
|
)?.icon || 'mdi-hand-coin-outline'
|
||||||
|
"
|
||||||
|
class="q-pr-sm"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{{ $t(`quotation.receiptDialog.${p.paymentStatus}`) }}
|
||||||
|
</span>
|
||||||
|
<q-icon name="mdi-chevron-down" class="q-pl-xs" />
|
||||||
|
<q-menu
|
||||||
|
ref="refQMenu"
|
||||||
|
fit
|
||||||
|
:offset="[0, 8]"
|
||||||
|
class="rounded"
|
||||||
|
>
|
||||||
|
<q-list dense>
|
||||||
|
<template
|
||||||
|
v-for="opts in paymentStatusOpts"
|
||||||
|
:key="opts.status"
|
||||||
|
>
|
||||||
|
<q-item
|
||||||
|
v-if="
|
||||||
|
(p.paymentStatus === 'PaymentWait' &&
|
||||||
|
opts.status !== 'PaymentRetry') ||
|
||||||
|
(p.paymentStatus === 'PaymentInProcess' &&
|
||||||
|
opts.status !== 'PaymentInProcess') ||
|
||||||
|
(p.paymentStatus === 'PaymentRetry' &&
|
||||||
|
opts.status !== 'PaymentRetry')
|
||||||
|
"
|
||||||
|
clickable
|
||||||
|
class="row items-center"
|
||||||
|
@click="selectStatus(p, opts.status, i)"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
:name="opts.icon"
|
||||||
|
:color="opts.color"
|
||||||
|
class="q-pr-sm"
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
|
{{ $t(opts.name) }}
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
</section>
|
</section>
|
||||||
<section class="row items-center q-px-md q-py-sm">
|
<section class="row items-center q-px-md q-py-sm">
|
||||||
{{ $t('quotation.receiptDialog.amountToBePaid') }}
|
{{ $t('quotation.receiptDialog.amountToBePaid') }}
|
||||||
|
|
@ -586,16 +708,26 @@ watch(
|
||||||
--_color: var(--orange-6-hsl / 0.2);
|
--_color: var(--orange-6-hsl / 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.payment-pending {
|
||||||
|
color: hsl(var(--warning-bg));
|
||||||
|
background: hsla(var(--warning-bg) / 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-process {
|
||||||
|
color: hsl(var(--danger-bg));
|
||||||
|
background: hsla(var(--danger-bg) / 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-retry {
|
||||||
|
color: hsl(var(--negative-bg));
|
||||||
|
background: hsla(var(--negative-bg) / 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
.payment-success {
|
.payment-success {
|
||||||
color: hsl(var(--positive-bg));
|
color: hsl(var(--positive-bg));
|
||||||
background: hsla(var(--positive-bg) / 0.1);
|
background: hsla(var(--positive-bg) / 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.payment-wait {
|
|
||||||
color: hsl(var(--warning-bg));
|
|
||||||
background: hsla(var(--warning-bg) / 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.urgent {
|
.urgent {
|
||||||
color: hsl(var(--red-6-hsl));
|
color: hsl(var(--red-6-hsl));
|
||||||
}
|
}
|
||||||
|
|
@ -636,4 +768,12 @@ watch(
|
||||||
border: 3px solid var(--border-color);
|
border: 3px solid var(--border-color);
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(
|
||||||
|
.q-expansion-item
|
||||||
|
.q-item.q-item-type.row.no-wrap.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable
|
||||||
|
.q-focus-helper
|
||||||
|
) {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue