262 lines
8.1 KiB
Vue
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>
|