feat: add new chart components for opportunity, quotation status, receipt, and sales
This commit is contained in:
parent
5ec7012119
commit
f168b43b1a
4 changed files with 371 additions and 0 deletions
58
src/pages/15_dash-board/chart/ChartOpportunity.vue
Normal file
58
src/pages/15_dash-board/chart/ChartOpportunity.vue
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
series: number[];
|
||||||
|
labels: string[];
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
labels: () => ['series-1', 'series-2', 'series-3', 'series-4'],
|
||||||
|
series: () => [1, 1, 1, 1],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const chartOptions = computed(() => ({
|
||||||
|
labels: props.labels,
|
||||||
|
colors: [
|
||||||
|
'#1F253B',
|
||||||
|
'#1B285C',
|
||||||
|
'#031B7D',
|
||||||
|
'#0023AE',
|
||||||
|
'#0933DA',
|
||||||
|
'#365AE9',
|
||||||
|
'#6380F8',
|
||||||
|
'#7583BB',
|
||||||
|
],
|
||||||
|
chart: {
|
||||||
|
fontFamily: 'Noto Sans Thai',
|
||||||
|
type: 'donut',
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
style: {
|
||||||
|
fontSize: '10px',
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
position: 'bottom',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="surface-1 rounded bordered q-pa-md">
|
||||||
|
{{ $t('dashboard.opportunity.title') }}
|
||||||
|
<div class="text-caption app-text-muted">
|
||||||
|
{{ $t('dashboard.opportunity.caption') }}
|
||||||
|
</div>
|
||||||
|
<VueApexCharts
|
||||||
|
type="donut"
|
||||||
|
height="200"
|
||||||
|
:options="chartOptions"
|
||||||
|
:series="series"
|
||||||
|
></VueApexCharts>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
107
src/pages/15_dash-board/chart/ChartQuotationStatus.vue
Normal file
107
src/pages/15_dash-board/chart/ChartQuotationStatus.vue
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
series: { data: number[] }[];
|
||||||
|
labels: string[];
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
series: () => [
|
||||||
|
{
|
||||||
|
data: [1, 2, 3, 4],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
labels: () => ['1', '2', '3', '4'],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const chartOptions = computed(() => ({
|
||||||
|
chart: {
|
||||||
|
type: 'bar',
|
||||||
|
fontFamily: 'Noto Sans Thai',
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
barHeight: '100%',
|
||||||
|
distributed: true,
|
||||||
|
horizontal: true,
|
||||||
|
borderRadius: 6,
|
||||||
|
borderRadiusApplication: 'end',
|
||||||
|
dataLabels: {
|
||||||
|
position: 'bottom',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colors: ['#f59f00', '#035aa1', '#0ca678', '#c92a2a'],
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false,
|
||||||
|
textAnchor: 'start',
|
||||||
|
style: {
|
||||||
|
colors: ['#fff'],
|
||||||
|
},
|
||||||
|
formatter: function (
|
||||||
|
val: string,
|
||||||
|
opt: {
|
||||||
|
w: { globals: { labels: { [x: string]: string } } };
|
||||||
|
dataPointIndex: string | number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
return opt.w.globals.labels[opt.dataPointIndex] + ': ' + val;
|
||||||
|
},
|
||||||
|
offsetX: 0,
|
||||||
|
dropShadow: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
width: 1,
|
||||||
|
colors: ['#fff'],
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories: props.labels,
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
theme: 'dark',
|
||||||
|
x: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
title: {
|
||||||
|
formatter: function (
|
||||||
|
val: string,
|
||||||
|
opt: {
|
||||||
|
w: { globals: { labels: { [x: string]: string } } };
|
||||||
|
dataPointIndex: string | number;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
return opt.w.globals.labels[opt.dataPointIndex] + ':';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="surface-1 rounded bordered q-pa-md">
|
||||||
|
{{ $t('dashboard.quotation.title') }}
|
||||||
|
<div class="text-caption app-text-muted">
|
||||||
|
{{ $t('dashboard.quotation.caption') }}
|
||||||
|
</div>
|
||||||
|
<VueApexCharts
|
||||||
|
type="bar"
|
||||||
|
height="200"
|
||||||
|
:options="chartOptions"
|
||||||
|
:series="series"
|
||||||
|
></VueApexCharts>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
131
src/pages/15_dash-board/chart/ChartReceipt.vue
Normal file
131
src/pages/15_dash-board/chart/ChartReceipt.vue
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
|
import DataDisplay from 'src/components/08_request-list/DataDisplay.vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { locale } = useI18n({ useScope: 'global' });
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
series: { name: string; data: number[] }[];
|
||||||
|
summary: number[];
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
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],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const chartOptions = computed(() => {
|
||||||
|
const thaiMonths = [
|
||||||
|
'ม.ค.',
|
||||||
|
'ก.พ.',
|
||||||
|
'มี.ค.',
|
||||||
|
'เม.ย.',
|
||||||
|
'พ.ค.',
|
||||||
|
'มิ.ย.',
|
||||||
|
'ก.ค.',
|
||||||
|
'ส.ค.',
|
||||||
|
'ก.ย.',
|
||||||
|
'ต.ค.',
|
||||||
|
'พ.ย.',
|
||||||
|
'ธ.ค.',
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
colors: ['#035aa1', '#ae3ec9', '#ffa94d', '#e64980'],
|
||||||
|
chart: {
|
||||||
|
fontFamily: 'Noto Sans Thai',
|
||||||
|
type: 'line',
|
||||||
|
zoom: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
position: 'right',
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories:
|
||||||
|
locale.value === 'tha'
|
||||||
|
? thaiMonths
|
||||||
|
: [
|
||||||
|
'Jan',
|
||||||
|
'Feb',
|
||||||
|
'Mar',
|
||||||
|
'Apr',
|
||||||
|
'May',
|
||||||
|
'Jun',
|
||||||
|
'Jul',
|
||||||
|
'Aug',
|
||||||
|
'Sep',
|
||||||
|
'Oct',
|
||||||
|
'Nov',
|
||||||
|
'Dec',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const detail = [
|
||||||
|
{
|
||||||
|
label: 'total',
|
||||||
|
color: 'var(--brand-1)',
|
||||||
|
icon: 'hugeicons:wallet-03',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'paid',
|
||||||
|
color: 'var(--purple-7)',
|
||||||
|
icon: 'material-symbols-light:credit-card-clock-outline-rounded',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'pending',
|
||||||
|
color: 'var(--orange-4)',
|
||||||
|
icon: 'material-symbols-light:credit-card-outline',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'cancel',
|
||||||
|
color: 'var(--pink-7)',
|
||||||
|
icon: 'hugeicons:wallet-remove-02',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="surface-1 rounded bordered q-pa-md">
|
||||||
|
{{ $t('dashboard.receipt.title') }}
|
||||||
|
<div class="text-caption app-text-muted">
|
||||||
|
{{ $t('dashboard.receipt.caption') }}
|
||||||
|
</div>
|
||||||
|
<VueApexCharts
|
||||||
|
type="line"
|
||||||
|
height="150"
|
||||||
|
:options="chartOptions"
|
||||||
|
:series="series"
|
||||||
|
></VueApexCharts>
|
||||||
|
|
||||||
|
<div class="row items-center">
|
||||||
|
<span
|
||||||
|
class="col-md col-6 row no-wrap items-center"
|
||||||
|
v-for="(v, i) in detail"
|
||||||
|
:key="v.label"
|
||||||
|
>
|
||||||
|
<q-avatar
|
||||||
|
class="q-mr-sm"
|
||||||
|
size="md"
|
||||||
|
font-size="18px"
|
||||||
|
:style="`background-color: ${v.color}; color: var(--surface-1)`"
|
||||||
|
>
|
||||||
|
<Icon :icon="v.icon" />
|
||||||
|
</q-avatar>
|
||||||
|
<DataDisplay
|
||||||
|
:label="$t(`dashboard.receipt.${v.label}`)"
|
||||||
|
:value="summary[i].toString()"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
75
src/pages/15_dash-board/chart/ChartSales.vue
Normal file
75
src/pages/15_dash-board/chart/ChartSales.vue
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import VueApexCharts from 'vue3-apexcharts';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const series = [
|
||||||
|
{
|
||||||
|
name: 'Net Profit',
|
||||||
|
data: [44, 55, 57, 56, 61, 58, 63, 60, 66],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Revenue',
|
||||||
|
data: [76, 85, 101, 98, 87, 105, 91, 114, 94],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Free Cash Flow',
|
||||||
|
data: [35, 41, 36, 26, 45, 48, 52, 53, 41],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const chartOptions = {
|
||||||
|
chart: {
|
||||||
|
type: 'bar',
|
||||||
|
fontFamily: 'Noto Sans Thai',
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
horizontal: false,
|
||||||
|
columnWidth: '55%',
|
||||||
|
borderRadius: 2,
|
||||||
|
borderRadiusApplication: 'end',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
show: true,
|
||||||
|
width: 2,
|
||||||
|
colors: ['transparent'],
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
categories: ['Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct'],
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
title: {
|
||||||
|
text: '$ (thousands)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
y: {
|
||||||
|
formatter: function (val: string) {
|
||||||
|
return '$ ' + val + ' thousands';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="surface-1 rounded bordered q-pa-md">
|
||||||
|
{{ $t('dashboard.sales.title') }}
|
||||||
|
<div class="text-caption app-text-muted">
|
||||||
|
{{ $t('dashboard.sales.caption') }}
|
||||||
|
</div>
|
||||||
|
<VueApexCharts
|
||||||
|
type="bar"
|
||||||
|
height="200"
|
||||||
|
:options="chartOptions"
|
||||||
|
:series="series"
|
||||||
|
></VueApexCharts>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue