echarts added to estadisticas page

This commit is contained in:
María
2025-08-22 16:09:27 +02:00
parent d7aeb1e98c
commit 4462fe0a4d
6 changed files with 227 additions and 37 deletions

117
components/LineChart.vue Normal file
View File

@@ -0,0 +1,117 @@
<template>
<!-- <section> -->
<div :id="chartId" class="chart-container ">
<div v-show="dialog && dialog.dataIndex !== -1" class="chart-dialog">
<p>this is a test</p>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import { nextTick } from 'vue';
// Import the tooltip, title, rectangular coordinate system, dataset and transform components
import {
DatasetComponent,
DataZoomComponent,
GridComponent,
LegendComponent,
TitleComponent,
TooltipComponent,
TransformComponent
} from 'echarts/components';
// Features like Universal Transition and Label Layout
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { SVGRenderer, CanvasRenderer } from 'echarts/renderers';
// Register the required components
echarts.use([
DatasetComponent,
DataZoomComponent,
GridComponent,
LabelLayout,
LegendComponent,
LineChart,
SVGRenderer,
TitleComponent,
TooltipComponent,
TransformComponent,
UniversalTransition,
CanvasRenderer
]);
export default {
props: {
chartId: {
type: String,
default: ''
},
lineChartData: {
type: Object,
default: () => { }
}
},
data() {
return {
chart: null,
showDataDialog: false,
dialog: {
top: 0,
left: 0,
dataIndex: -1,
}
}
},
computed: {
chartContainer() {
return document.getElementById(this.chartId)
}
},
watch: {
lineChartData: {
immediate: true,
deep: true,
handler(newVal) {
if (newVal && newVal.xAxis && newVal.series) {
this.$nextTick(() => {
const el = document.getElementById(this.chartId);
if (el && el.clientWidth > 0 && el.clientHeight > 0) {
this.initChart();
}
});
}
}
}
},
methods: {
initChart() {
this.chart = echarts.init(this.chartContainer, {
renderer: 'svg',
useDirtyRect: false,
decalPattern: true,
});
this.chart.setOption(this.lineChartData)
this.chart.resize();
},
},
}
</script>
<style>
.chart-container {
position: relative;
width: 100%;
height: 24rem;
color: #000000;
}
.chart-dialog {
position: absolute;
z-index: 10;
width: 6rem;
height: 6rem;
background-color: #ffffff;
}
</style>

View File

@@ -5,20 +5,14 @@
<header> <header>
<strong class="title">{{ name }}</strong> <strong class="title">{{ name }}</strong>
</header> </header>
<div class="period"> <div v-if="info" class="period">
<span class="period-text">{{ info.month }}</span> <span class="period-text">{{ info?.month }}</span>
<strong class="value">{{ info?.value }}</strong>
</div> </div>
<strong class="value">{{ info.value }}</strong>
</div> </div>
<div class="chart"> <div class="chart">
<ClientOnly> <ClientOnly>
<TrendChart <LineChart :chart-id="chartId" :line-chart-data="dataset" />
:datasets="[dataset]"
padding="5 0 0 5"
:min="0"
:interactive="true"
@mouse-move="onMouseMove"
/>
</ClientOnly> </ClientOnly>
</div> </div>
</div> </div>
@@ -32,6 +26,10 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
chartId: {
type: String,
default: '',
},
values: { values: {
type: Array, type: Array,
default: () => [], default: () => [],
@@ -60,15 +58,41 @@ export default {
'Noviembre', 'Noviembre',
'Diciembre', 'Diciembre',
], ],
abrevMonths: [
'Ene',
'Feb',
'Mar',
'Abr',
'May',
'Jun',
'Jul',
'Ago',
'Sep',
'Oct',
'Nov',
'Dic',
]
} }
}, },
computed: { computed: {
dataset() { dataset() {
return { return {
data: this.values, xAxis: {
showPoints: true, type: 'category',
fill: true, data: this.abrevMonths
},
yAxis: {
type: 'value'
},
series: [
{
data: this.yAxisValues,
type: 'line',
smooth: true, smooth: true,
color: this.color
}
]
} }
}, },
cssProps() { cssProps() {
@@ -77,26 +101,37 @@ export default {
} }
}, },
info() { info() {
return { const actualMonth = new Date().getMonth();
month: this.currentInfo ? this.currentInfo.month : 'Este mes', const currentMonthInfo = this.values.sort((a, b) => a.month - b.month)[actualMonth];
value: this.currentInfo const res = {
? this.currentInfo.value month: currentMonthInfo?.month ? this.months[actualMonth] : 'Este mes',
: this.values[11].value, value: currentMonthInfo?.value ? currentMonthInfo?.value : 0,
} };
return res;
},
yAxisValues(){
const ArrValues = [...this.values]
const res = [];
ArrValues.sort((a, b) => a.month - b.month)
ArrValues.forEach(item => {
res.push(item.value)
})
return res
}, },
}, },
methods: { methods: {
onMouseMove(params) { // onMouseMove(params) {
if (params) { // if (params) {
this.currentInfo = { // this.currentInfo = {
month: this.months[params.data[0].month - 1], // month: this.months[params.data[0].month - 1],
value: params.data[0].value, // value: params.data[0].value,
} // }
} else { // } else {
this.currentInfo = null // this.currentInfo = null
} // }
}, // },
}, },
} }
</script> </script>
@@ -111,11 +146,16 @@ export default {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
width: 100%; width: 100%;
.period {
display: flex;
flex-direction: column-reverse;
}
.value { .value {
font-size: 30px; font-size: 30px;
} }
.chart { .chart {
width: 40%; width: 40%;
} }
} }
.stroke { .stroke {

32
package-lock.json generated
View File

@@ -13,6 +13,7 @@
"@nuxtjs/sitemap": "^7.4.3", "@nuxtjs/sitemap": "^7.4.3",
"@pinia/nuxt": "^0.11.2", "@pinia/nuxt": "^0.11.2",
"dompurify": "^3.2.6", "dompurify": "^3.2.6",
"echarts": "^6.0.0",
"eslint": "^9.32.0", "eslint": "^9.32.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"nuxt": "^3.17.7", "nuxt": "^3.17.7",
@@ -7132,6 +7133,22 @@
"integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==", "integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/echarts": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz",
"integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "2.3.0",
"zrender": "6.0.0"
}
},
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"license": "0BSD"
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -14656,6 +14673,21 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
},
"node_modules/zrender": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-6.0.0.tgz",
"integrity": "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==",
"license": "BSD-3-Clause",
"dependencies": {
"tslib": "2.3.0"
}
},
"node_modules/zrender/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"license": "0BSD"
} }
} }
} }

View File

@@ -16,6 +16,7 @@
"@nuxtjs/sitemap": "^7.4.3", "@nuxtjs/sitemap": "^7.4.3",
"@pinia/nuxt": "^0.11.2", "@pinia/nuxt": "^0.11.2",
"dompurify": "^3.2.6", "dompurify": "^3.2.6",
"echarts": "^6.0.0",
"eslint": "^9.32.0", "eslint": "^9.32.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"nuxt": "^3.17.7", "nuxt": "^3.17.7",

View File

@@ -14,33 +14,33 @@
</p> </p>
</div> </div>
</div> </div>
{{ companiesTimeline }}
{{ productsTimeline }}
{{ usersTimeline }}
{{ contactTimeline }}
{{ shoppingTimeline }}
<hr /> <hr />
<trend-stats <trend-stats
:chart-id="`1`"
:color="`#39af77`" :color="`#39af77`"
:name="`Nuevas cooperativas`" :name="`Nuevas cooperativas`"
:values="companiesTimeline" :values="companiesTimeline"
/> />
<trend-stats <trend-stats
:chart-id="`2`"
:color="`red`" :color="`red`"
:name="`Nuevos productos`" :name="`Nuevos productos`"
:values="productsTimeline" :values="productsTimeline"
/> />
<trend-stats <trend-stats
:chart-id="`3`"
:color="`purple`" :color="`purple`"
:name="`Nuevos usuarios`" :name="`Nuevos usuarios`"
:values="usersTimeline" :values="usersTimeline"
/> />
<trend-stats <trend-stats
:chart-id="`4`"
:color="`blue`" :color="`blue`"
:name="`Contactados`" :name="`Contactados`"
:values="contactTimeline" :values="contactTimeline"
/> />
<trend-stats <trend-stats
:chart-id="`5`"
:color="`orange`" :color="`orange`"
:name="`Redirecciones a producto`" :name="`Redirecciones a producto`"
:values="shoppingTimeline" :values="shoppingTimeline"

View File

@@ -11,7 +11,7 @@ export const useAuthStore = defineStore('auth', {
role: 'ANON' as string, role: 'ANON' as string,
cookiesAreAccepted: false, cookiesAreAccepted: false,
}), }),
persist: true, // Enable persistence. Cookies will be stored 'auth' //persist: true, // TODO: Enable persistence. Cookies will be stored 'auth'
getters: { getters: {
isAuthenticated: (state) => !!state.access, isAuthenticated: (state) => !!state.access,
isUser: (state) => state.role === 'SHOP_USER', isUser: (state) => state.role === 'SHOP_USER',