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