Files
pdf_oralia_vibe/frontend/src/components/analytics/MonthlyChart.vue
Bertrand Benjamin 14b39efe3b refactor(ui): aligne les composants de donnees sur le design system
Cartes, en-tetes, champs de filtre, tableaux, badges, paginations et
indicateurs de chargement des tableaux de bord etaient proches mais
jamais identiques (bordure presente ou absente, paddings et arrondis
variables). Ils utilisent maintenant les classes communes.

Les colonnes tronquees des tableaux sont elargies et les sept filtres
des depenses tiennent sur une ligne, la largeur retrouvee le permettant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:50:26 +02:00

108 lines
2.2 KiB
Vue

<template>
<div class="card card-body">
<h3 class="card-title block mb-4">Evolution mensuelle</h3>
<div class="h-64">
<Bar
v-if="chartData.labels.length > 0"
:data="chartData"
:options="chartOptions"
/>
<div v-else class="h-full flex items-center justify-center text-gray-500 text-sm">
Aucune donnee
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { Bar } from 'vue-chartjs'
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
} from 'chart.js'
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
const props = defineProps({
data: {
type: Array,
default: () => []
}
})
const monthNames = [
'Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Juin',
'Juil', 'Aout', 'Sep', 'Oct', 'Nov', 'Dec'
]
const chartData = computed(() => {
const items = props.data.slice(-24) // Last 24 months
return {
labels: items.map(d => `${monthNames[d.month - 1]} ${d.year}`),
datasets: [
{
label: 'Debit',
data: items.map(d => d.total_debit),
backgroundColor: '#EF4444',
borderRadius: 4
},
{
label: 'Credit',
data: items.map(d => d.total_credit),
backgroundColor: '#10B981',
borderRadius: 4
}
]
}
})
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
labels: {
color: '#9CA3AF',
font: { size: 11 },
boxWidth: 12,
padding: 15
}
},
tooltip: {
callbacks: {
label: (ctx) => {
const value = new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR'
}).format(ctx.raw)
return ` ${ctx.dataset.label}: ${value}`
}
}
}
},
scales: {
x: {
ticks: { color: '#6B7280', font: { size: 10 } },
grid: { color: '#374151' }
},
y: {
ticks: {
color: '#6B7280',
callback: (value) => {
if (value >= 1000) return `${(value / 1000).toFixed(0)}k`
return value
}
},
grid: { color: '#374151' }
}
}
}
</script>