jws-frontend/src/pages/15_dash-board/MainPage.vue
puriphatt 22f9b43c38
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 6s
feat: add tooltip to date range selector in MainPage
2025-03-10 14:53:59 +07:00

262 lines
8.1 KiB
Vue

<script lang="ts" setup>
// NOTE: Library
import { onMounted, reactive, watch } from 'vue';
// NOTE: Components
import SelectInput from 'src/components/shared/SelectInput.vue';
import StatCardComponent from 'src/components/StatCardComponent.vue';
import ChartReceipt from './chart/ChartReceipt.vue';
import ChartQuotationStatus from './chart/ChartQuotationStatus.vue';
import VueDatePicker from '@vuepic/vue-datepicker';
// import ChartOpportunity from './chart/ChartOpportunity.vue';
// import ChartSales from './chart/ChartSales.vue';
// NOTE: Stores & Type
import { useNavigator } from 'src/stores/navigator';
import { useQuotationStore } from 'src/stores/quotations';
import { storeToRefs } from 'pinia';
import { useReportStore } from 'src/stores/report';
import { PaymentDataStatus } from 'src/stores/payment/types';
import { dateFormatJS } from 'src/utils/datetime';
// NOTE: Variable
const navigatorStore = useNavigator();
const quotationStore = useQuotationStore();
const reportStore = useReportStore();
const { stats: quotationStats } = storeToRefs(quotationStore);
const { dataReportPayment } = storeToRefs(reportStore);
const endDate = new Date();
const startDate = new Date(new Date().setFullYear(endDate.getFullYear() - 1));
const state = reactive({
role: 'admin',
date: [startDate, endDate],
});
// const option = reactive({
// role: [
// { label: 'ผู้ดูแล', value: 'admin' },
// { label: 'ผู้ใช้', value: 'user' },
// ],
// });
async function fetchData() {
const ret = await quotationStore.getQuotationStats({
startDate: state.date[0],
endDate: state.date[1],
});
if (ret) {
quotationStats.value = {
issued: 0,
accepted: 0,
expired: 0,
paymentInProcess: 0,
paymentSuccess: 0,
processComplete: 0,
canceled: 0,
};
quotationStats.value = Object.assign(quotationStats.value, ret);
}
const retPayment = await reportStore.getReportPayment({
startDate: state.date[0],
endDate: state.date[1],
});
if (retPayment) {
dataReportPayment.value = retPayment;
}
}
onMounted(async () => {
navigatorStore.current.title = 'dashboard.title';
navigatorStore.current.path = [{ text: '' }];
await fetchData();
});
watch(
() => state.date,
async () => {
await fetchData();
},
);
</script>
<template>
<div class="column full-height no-wrap">
<header class="row q-gutter-sm">
<!-- <SelectInput
class="col-md-3 col"
:option="option.role"
v-model="state.role"
for="selecte-role"
></SelectInput> -->
<VueDatePicker
utc
range
teleport
auto-apply
for="select-date-range"
class="col-md-3 col"
v-model="state.date"
:dark="$q.dark.isActive"
:locale="$i18n.locale === 'tha' ? 'th' : 'en'"
>
<template #trigger>
<q-input
placeholder="DD/MM/YYYY"
hide-bottom-space
dense
outlined
for="select-date-range"
:model-value="
dateFormatJS({ date: state.date[0] }) +
' - ' +
dateFormatJS({ date: state.date[1] })
"
>
<template #prepend>
<q-icon name="mdi-calendar-outline" class="app-text-muted" />
</template>
<q-tooltip>
{{
dateFormatJS({ date: state.date[0] }) +
' - ' +
dateFormatJS({ date: state.date[1] })
}}
</q-tooltip>
</q-input>
</template>
</VueDatePicker>
<div class="col-12 scroll">
<div style="display: inline-block">
<StatCardComponent
:dark="$q.dark.isActive"
text-size="10px"
:branch="[
{
icon: 'material-symbols-light:receipt-long',
count:
(quotationStats.issued || 0) +
(quotationStats.accepted || 0) +
(quotationStats.paymentInProcess || 0) +
(quotationStats.paymentSuccess || 0) +
(quotationStats.processComplete || 0) +
(quotationStats.canceled || 0),
label: $t('dashboard.openQuotation'),
color: 'cyan',
},
{
icon: 'si:wallet-detailed-line',
count:
(quotationStats.paymentSuccess || 0) +
(quotationStats.processComplete || 0),
label: $t('dashboard.paidSales'),
color: 'light-yellow',
},
{
icon: 'fluent:money-hand-24-regular',
count:
(quotationStats.issued || 0) +
(quotationStats.accepted || 0) +
(quotationStats.paymentInProcess || 0),
label: $t('dashboard.pendingSales'),
color: 'light-purple',
},
]"
/>
</div>
</div>
</header>
<section class="col q-mt-md">
<div class="full-height scroll">
<article class="row q-col-gutter-sm">
<div class="col-sm-8 col-12">
<ChartReceipt
class="full-height"
:summary="[
dataReportPayment.reduce(
(a, c) =>
a +
(c.data[PaymentDataStatus.Success] || 0) +
(c.data[PaymentDataStatus.Wait] || 0),
0,
),
dataReportPayment.reduce(
(a, c) => a + (c.data[PaymentDataStatus.Success] || 0),
0,
),
dataReportPayment.reduce(
(a, c) => a + (c.data[PaymentDataStatus.Wait] || 0),
0,
),
]"
:categories="
dataReportPayment.map((v) => v.month + ' / ' + v.year)
"
:series="[
{
name: $t('dashboard.receipt.total'),
data: dataReportPayment.map(
(v) =>
(v.data[PaymentDataStatus.Success] || 0) +
(v.data[PaymentDataStatus.Wait] || 0),
),
},
{
name: $t('dashboard.receipt.paid'),
data: dataReportPayment.map(
(v) => v.data[PaymentDataStatus.Success] || 0,
),
},
{
name: $t('dashboard.receipt.pending'),
data: dataReportPayment.map(
(v) => v.data[PaymentDataStatus.Wait] || 0,
),
},
]"
/>
</div>
<!-- <div class="col-sm-4 col-12">
<ChartOpportunity
class="full-height"
:labels="['1', '2', '3', '4', '5', '6', '7', '8']"
:series="[581, 389, 609, 581, 603, 600, 699, 347]"
/>
</div> -->
<div class="col-sm-4 col-12">
<ChartQuotationStatus
v-if="quotationStats"
class="full-height"
:labels="[
$t('dashboard.quotation.waitCustomer'),
$t('dashboard.quotation.inProgress'),
$t('dashboard.quotation.complete'),
$t('dashboard.quotation.cancel'),
]"
:series="[
{
data: [
(quotationStats.issued || 0) +
(quotationStats.accepted || 0),
(quotationStats.paymentInProcess || 0) +
(quotationStats.paymentSuccess || 0),
quotationStats.processComplete || 0,
quotationStats.canceled || 0,
],
},
]"
/>
</div>
<!-- <div class="col-sm-8 col-12">
<ChartSales class="full-height" />
</div> -->
</article>
</div>
</section>
</div>
</template>
<style scoped></style>