feat: dashboard data bind api
This commit is contained in:
parent
9a196b7077
commit
58b5613d2c
6 changed files with 100 additions and 59 deletions
|
|
@ -1,7 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||
import { formatNumberDecimal } from 'src/stores/utils';
|
||||
|
||||
defineEmits<{ (e: 'labelClick', value: string, index: number): void }>();
|
||||
defineEmits<{ (e: 'labelClick', value: string, index: number | null): void }>();
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
|
|
@ -38,7 +39,7 @@ withDefaults(
|
|||
v-if="typeof value === 'string'"
|
||||
@click="$emit('labelClick', value, null)"
|
||||
>
|
||||
{{ value }}
|
||||
{{ formatNumberDecimal(+value, 2) }}
|
||||
<q-tooltip v-if="tooltip" :delay="500">{{ value }}</q-tooltip>
|
||||
</span>
|
||||
<span v-else :class="{ 'link cursor-pointer': clickable }">
|
||||
|
|
|
|||
|
|
@ -1362,7 +1362,7 @@ export default {
|
|||
title: 'สรุปยอดใบกำกับภาษี',
|
||||
caption: 'ตามจำนวนเงินรวม',
|
||||
total: 'ยอดรวมทั้งหมด',
|
||||
paid: 'ชำระไม่ครบและชำระครบ',
|
||||
paid: 'ชำระแล้ว',
|
||||
pending: 'รอชำระ',
|
||||
cancel: 'ยกเลิก',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,11 +14,15 @@ import ChartSales from './chart/ChartSales.vue';
|
|||
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';
|
||||
|
||||
// NOTE: Variable
|
||||
const navigatorStore = useNavigator();
|
||||
const quotationStore = useQuotationStore();
|
||||
const reportStore = useReportStore();
|
||||
const { stats: quotationStats } = storeToRefs(quotationStore);
|
||||
const { dataReportPayment } = storeToRefs(reportStore);
|
||||
|
||||
const state = reactive({
|
||||
role: 'admin',
|
||||
|
|
@ -46,6 +50,12 @@ onMounted(async () => {
|
|||
quotationStats.value = Object.assign(quotationStats.value, ret);
|
||||
console.log(quotationStats.value);
|
||||
}
|
||||
|
||||
const retPayment = await reportStore.getReportPayment();
|
||||
|
||||
if (retPayment) {
|
||||
dataReportPayment.value = retPayment;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
|
|
@ -72,27 +82,32 @@ onMounted(async () => {
|
|||
:dark="$q.dark.isActive"
|
||||
text-size="10px"
|
||||
:branch="[
|
||||
{
|
||||
icon: 'mdi-account-outline',
|
||||
count: 0,
|
||||
label: $t('dashboard.newComer'),
|
||||
color: 'pink',
|
||||
},
|
||||
{
|
||||
icon: 'material-symbols-light:receipt-long',
|
||||
count: 0,
|
||||
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: 0,
|
||||
count:
|
||||
(quotationStats.paymentSuccess || 0) +
|
||||
(quotationStats.processComplete || 0),
|
||||
label: $t('dashboard.paidSales'),
|
||||
color: 'light-yellow',
|
||||
},
|
||||
{
|
||||
icon: 'fluent:money-hand-24-regular',
|
||||
count: 0,
|
||||
count:
|
||||
(quotationStats.issued || 0) +
|
||||
(quotationStats.accepted || 0) +
|
||||
(quotationStats.paymentInProcess || 0),
|
||||
label: $t('dashboard.pendingSales'),
|
||||
color: 'light-purple',
|
||||
},
|
||||
|
|
@ -108,34 +123,57 @@ onMounted(async () => {
|
|||
<div class="col-sm-8 col-12">
|
||||
<ChartReceipt
|
||||
class="full-height"
|
||||
:summary="[45, 30, 10, 5]"
|
||||
: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: [45, 78, 92, 34, 67, 89, 120, 150, 180, 200, 50],
|
||||
data: dataReportPayment.map(
|
||||
(v) =>
|
||||
(v.data[PaymentDataStatus.Success] || 0) +
|
||||
(v.data[PaymentDataStatus.Wait] || 0),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: $t('dashboard.receipt.paid'),
|
||||
data: [30, 50, 70, 20, 40, 65, 80, 130, 160, 190, 210],
|
||||
data: dataReportPayment.map(
|
||||
(v) => v.data[PaymentDataStatus.Success] || 0,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: $t('dashboard.receipt.pending'),
|
||||
data: [10, 25, 45, 30, 50, 60, 75, 95, 110, 130, 150],
|
||||
},
|
||||
{
|
||||
name: $t('dashboard.receipt.cancel'),
|
||||
data: [5, 20, 15, 25, 35, 40, 55, 70, 85, 100, 300],
|
||||
data: dataReportPayment.map(
|
||||
(v) => v.data[PaymentDataStatus.Wait] || 0,
|
||||
),
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-sm-4 col-12">
|
||||
<!-- <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> -->
|
||||
<div class="col-sm-4 col-12">
|
||||
<ChartQuotationStatus
|
||||
v-if="quotationStats"
|
||||
|
|
@ -148,23 +186,21 @@ onMounted(async () => {
|
|||
]"
|
||||
:series="[
|
||||
{
|
||||
data: true
|
||||
? []
|
||||
: [
|
||||
quotationStats.issued || 0,
|
||||
quotationStats.accepted +
|
||||
quotationStats.paymentInProcess +
|
||||
quotationStats.paymentSuccess || 1,
|
||||
quotationStats.processComplete || 1,
|
||||
quotationStats.canceled || 1,
|
||||
],
|
||||
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">
|
||||
<!-- <div class="col-sm-8 col-12">
|
||||
<ChartSales class="full-height" />
|
||||
</div>
|
||||
</div> -->
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -6,19 +6,20 @@ import { computed } from 'vue';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
const { locale } = useI18n({ useScope: 'global' });
|
||||
|
||||
withDefaults(
|
||||
const prop = withDefaults(
|
||||
defineProps<{
|
||||
series: { name: string; data: number[] }[];
|
||||
summary: number[];
|
||||
categories: string[];
|
||||
}>(),
|
||||
{
|
||||
series: () => [
|
||||
{ name: 'series-1', data: [0, 0] },
|
||||
{ name: 'series-2', data: [1, 1] },
|
||||
{ name: 'series-3', data: [2, 2] },
|
||||
{ name: 'series-4', data: [3, 3] },
|
||||
],
|
||||
summary: () => [0, 0, 0, 0],
|
||||
categories: () => ['Jan', 'Feb', 'Mar'],
|
||||
},
|
||||
);
|
||||
const chartOptions = computed(() => {
|
||||
|
|
@ -50,23 +51,7 @@ const chartOptions = computed(() => {
|
|||
position: 'right',
|
||||
},
|
||||
xaxis: {
|
||||
categories:
|
||||
locale.value === 'tha'
|
||||
? thaiMonths
|
||||
: [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec',
|
||||
],
|
||||
categories: prop.categories,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -87,11 +72,6 @@ const detail = [
|
|||
color: 'var(--orange-4)',
|
||||
icon: 'material-symbols-light:credit-card-outline',
|
||||
},
|
||||
{
|
||||
label: 'cancel',
|
||||
color: 'var(--pink-7)',
|
||||
icon: 'hugeicons:wallet-remove-02',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,13 @@ import { ref } from 'vue';
|
|||
import { defineStore } from 'pinia';
|
||||
import { Pagination, Status } from '../types';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { Report, ReportProduct, ReportQuotation, ReportSale } from './types';
|
||||
import {
|
||||
Report,
|
||||
ReportPayment,
|
||||
ReportProduct,
|
||||
ReportQuotation,
|
||||
ReportSale,
|
||||
} from './types';
|
||||
|
||||
const ENDPOINT = 'report';
|
||||
|
||||
|
|
@ -48,12 +54,21 @@ export async function getReportProduct() {
|
|||
return null;
|
||||
}
|
||||
|
||||
export async function getReportPayment() {
|
||||
const res = await api.get<ReportPayment[]>(`/${ENDPOINT}/payment`);
|
||||
if (res.status < 400) {
|
||||
return res.data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const useReportStore = defineStore('report-store', () => {
|
||||
const dataReportQuotation = ref<ReportQuotation[]>([]);
|
||||
const dataReportInvoice = ref<Report[]>([]);
|
||||
const dataReportReceipt = ref<Report[]>([]);
|
||||
const dataReportSale = ref<ReportSale>();
|
||||
const dataReportProduct = ref<ReportProduct[]>([]);
|
||||
const dataReportPayment = ref<ReportPayment[]>([]);
|
||||
|
||||
return {
|
||||
dataReportQuotation,
|
||||
|
|
@ -61,11 +76,13 @@ export const useReportStore = defineStore('report-store', () => {
|
|||
dataReportReceipt,
|
||||
dataReportSale,
|
||||
dataReportProduct,
|
||||
dataReportPayment,
|
||||
|
||||
getReportQuotation,
|
||||
getReportInvoice,
|
||||
getReportReceipt,
|
||||
getReportSale,
|
||||
getReportProduct,
|
||||
getReportPayment,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { QuotationStatus } from 'src/stores/quotations/types';
|
|||
import { ProductGroup } from '../product-service/types';
|
||||
import { User } from '../user';
|
||||
import { CustomerBranch } from '../customer';
|
||||
import { PaymentDataStatus } from '../payment/types';
|
||||
|
||||
export type ReportQuotation = {
|
||||
updatedAt: Date | null;
|
||||
|
|
@ -34,6 +35,12 @@ export type ReportProduct = {
|
|||
code: string;
|
||||
};
|
||||
|
||||
export type ReportPayment = {
|
||||
year: string;
|
||||
month: string;
|
||||
data: Partial<Record<PaymentDataStatus, number>>;
|
||||
};
|
||||
|
||||
export type ReportSale = {
|
||||
byCustomer: (Omit<CustomerBranch, '_count'> & { _count: number })[];
|
||||
bySale: (User & { _count: number })[];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue