|
|
@@ -1,183 +1,419 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
<DefaultHeaderPage />
|
|
|
+
|
|
|
+ <div class="q-pa-md">
|
|
|
+ <!-- Row 1: Stats -->
|
|
|
+ <div class="row q-col-gutter-md q-mb-md">
|
|
|
+ <div class="col-12 col-sm-6 col-lg-3">
|
|
|
+ <q-card flat bordered>
|
|
|
+ <q-card-section class="row justify-between items-start q-pb-none">
|
|
|
+ <span class="text-caption text-grey-6">Total alunos (contratos ativos)</span>
|
|
|
+ <q-icon name="mdi-account-multiple" color="grey-4" size="sm" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-card-section class="q-pt-sm">
|
|
|
+ <div class="text-h5 text-bold">0</div>
|
|
|
+ <q-badge color="orange" class="q-mt-sm q-pa-xs" style="font-size: 11px">
|
|
|
+ 0 ativos
|
|
|
+ </q-badge>
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-12 col-sm-6 col-lg-3">
|
|
|
+ <q-card flat bordered>
|
|
|
+ <q-card-section class="row justify-between items-start q-pb-none">
|
|
|
+ <span class="text-caption text-grey-6">Receita Total</span>
|
|
|
+ <q-icon name="mdi-currency-usd" color="grey-4" size="sm" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-card-section class="q-pt-sm">
|
|
|
+ <div class="text-h5 text-bold">R$ 0,00</div>
|
|
|
+ <div class="text-caption text-grey-5 q-mt-sm">0 pagamentos pendentes</div>
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-12 col-sm-6 col-lg-3">
|
|
|
+ <q-card flat bordered>
|
|
|
+ <q-card-section class="row justify-between items-start q-pb-none">
|
|
|
+ <span class="text-caption text-grey-6">Ticket Médio</span>
|
|
|
+ <q-icon name="mdi-receipt-outline" color="grey-4" size="sm" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-card-section class="q-pt-sm">
|
|
|
+ <div class="text-h5 text-bold">R$ 12,00</div>
|
|
|
+ <div class="text-caption text-grey-5 q-mt-sm">Estável</div>
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-12 col-sm-6 col-lg-3">
|
|
|
+ <q-card flat bordered>
|
|
|
+ <q-card-section class="row justify-between items-start q-pb-none">
|
|
|
+ <span class="text-caption text-grey-6">Aniversariantes</span>
|
|
|
+ <q-icon name="mdi-emoticon-outline" color="grey-4" size="sm" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-card-section class="q-pt-sm">
|
|
|
+ <div class="text-h5 text-bold">0</div>
|
|
|
+ <div class="text-caption text-grey-5 q-mt-sm">Fortaleça seus relacionamentos</div>
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Row 2: Charts -->
|
|
|
+ <div class="row q-col-gutter-md q-mb-md">
|
|
|
+ <!-- Faturamento Serviço / Materiais -->
|
|
|
+ <div class="col-12 col-md-5">
|
|
|
+ <q-card flat bordered style="height: 280px">
|
|
|
+ <q-card-section class="row justify-between items-center q-pb-xs">
|
|
|
+ <span class="text-subtitle2 text-weight-medium">Faturamento Serviço / Materiais</span>
|
|
|
+ <q-icon name="mdi-book-open-outline" color="grey-5" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <q-card-section style="height: calc(100% - 57px)" class="q-pt-sm q-px-sm">
|
|
|
+ <Bar :data="faturamentoData" :options="faturamentoOptions" />
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Contratos Ativos -->
|
|
|
+ <div class="col-12 col-md-4">
|
|
|
+ <q-card flat bordered style="height: 280px">
|
|
|
+ <q-card-section class="row justify-between items-center q-pb-xs">
|
|
|
+ <span class="text-subtitle2 text-weight-medium">Contratos Ativos</span>
|
|
|
+ <q-icon name="mdi-trending-up" color="grey-5" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <q-card-section
|
|
|
+ class="flex flex-center q-pt-sm"
|
|
|
+ style="height: calc(100% - 57px); position: relative"
|
|
|
+ >
|
|
|
+ <div style="height: 100%; max-width: 280px; width: 100%">
|
|
|
+ <Doughnut
|
|
|
+ :data="gaugeData"
|
|
|
+ :options="gaugeOptions"
|
|
|
+ :plugins="[gaugeNeedlePlugin]"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="gauge-label">
|
|
|
+ <div class="text-h5 text-bold">70</div>
|
|
|
+ <div class="text-caption text-grey-6">Grade</div>
|
|
|
+ </div>
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Atalhos rápidos -->
|
|
|
+ <div class="col-12 col-md-3">
|
|
|
+ <q-card flat bordered style="height: 280px">
|
|
|
+ <q-card-section class="row justify-between items-center q-pb-xs">
|
|
|
+ <span class="text-subtitle2 text-weight-medium">Atalhos rápidos</span>
|
|
|
+ <q-icon name="mdi-apps" color="grey-5" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <q-card-section class="q-pt-md column q-gutter-sm">
|
|
|
+ <q-btn
|
|
|
+ unelevated
|
|
|
+ color="primary"
|
|
|
+ label="Criar contrato"
|
|
|
+ no-caps
|
|
|
+ class="full-width"
|
|
|
+ />
|
|
|
+ <q-btn
|
|
|
+ unelevated
|
|
|
+ color="primary"
|
|
|
+ label="Registrar presença"
|
|
|
+ no-caps
|
|
|
+ class="full-width"
|
|
|
+ />
|
|
|
+ <q-btn
|
|
|
+ unelevated
|
|
|
+ color="primary"
|
|
|
+ label="Novo pedido"
|
|
|
+ no-caps
|
|
|
+ class="full-width"
|
|
|
+ />
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Row 3: Bottom -->
|
|
|
+ <div class="row q-col-gutter-md">
|
|
|
+ <!-- Matrículas por Período -->
|
|
|
+ <div class="col-12 col-md-4">
|
|
|
+ <q-card flat bordered style="height: 320px">
|
|
|
+ <q-card-section class="row justify-between items-center q-pb-xs">
|
|
|
+ <span class="text-subtitle2 text-weight-medium">Matrículas por Período</span>
|
|
|
+ <q-icon name="mdi-book-open-outline" color="grey-5" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <q-card-section style="height: calc(100% - 57px)" class="q-pt-sm q-px-sm">
|
|
|
+ <Bar
|
|
|
+ :data="matriculasData"
|
|
|
+ :options="matriculasOptions"
|
|
|
+ :plugins="[ChartDataLabels]"
|
|
|
+ />
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Aniversariantes do Mês -->
|
|
|
+ <div class="col-12 col-md-4">
|
|
|
+ <q-card flat bordered style="height: 320px">
|
|
|
+ <q-card-section class="row justify-between items-center q-pb-xs">
|
|
|
+ <span class="text-subtitle2 text-weight-medium">Aniversariantes do Mês</span>
|
|
|
+ <q-icon name="mdi-gift-outline" color="grey-5" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <div class="row justify-between items-center q-px-md q-py-xs">
|
|
|
+ <span class="text-caption text-grey-6">Nome</span>
|
|
|
+ <span class="text-caption text-grey-6">Ações</span>
|
|
|
+ </div>
|
|
|
+ <q-separator />
|
|
|
+ <div style="height: calc(100% - 105px); overflow-y: auto">
|
|
|
+ <q-list separator>
|
|
|
+ <q-item v-for="(pessoa, i) in aniversariantes" :key="i" dense class="q-py-sm">
|
|
|
+ <q-item-section avatar>
|
|
|
+ <q-avatar :color="pessoa.color" text-color="white" size="34px" class="text-caption text-bold">
|
|
|
+ {{ pessoa.nome[0] }}
|
|
|
+ </q-avatar>
|
|
|
+ </q-item-section>
|
|
|
+ <q-item-section>
|
|
|
+ <q-item-label>{{ pessoa.nome }}</q-item-label>
|
|
|
+ </q-item-section>
|
|
|
+ <q-item-section side>
|
|
|
+ <div class="row">
|
|
|
+ <q-btn flat dense round icon="mdi-whatsapp" color="green" size="sm" />
|
|
|
+ <q-btn flat dense round icon="mdi-email-outline" color="grey-6" size="sm" />
|
|
|
+ </div>
|
|
|
+ </q-item-section>
|
|
|
+ </q-item>
|
|
|
+ </q-list>
|
|
|
+ </div>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Feriados do mês -->
|
|
|
+ <div class="col-12 col-md-4">
|
|
|
+ <q-card flat bordered style="height: 320px">
|
|
|
+ <q-card-section class="row justify-between items-center q-pb-xs">
|
|
|
+ <span class="text-subtitle2 text-weight-medium">Feriados do mês</span>
|
|
|
+ <q-icon name="mdi-calendar-outline" color="grey-5" />
|
|
|
+ </q-card-section>
|
|
|
+ <q-separator />
|
|
|
+ <q-card-section class="q-pt-md">
|
|
|
+ <q-btn
|
|
|
+ unelevated
|
|
|
+ color="primary"
|
|
|
+ label="Nova data"
|
|
|
+ no-caps
|
|
|
+ class="full-width q-mb-md"
|
|
|
+ />
|
|
|
+ <div class="row q-gutter-sm">
|
|
|
+ <div
|
|
|
+ v-for="(feriado, i) in feriados"
|
|
|
+ :key="i"
|
|
|
+ class="column items-center"
|
|
|
+ style="min-width: 52px"
|
|
|
+ >
|
|
|
+ <q-badge
|
|
|
+ :color="feriado.color"
|
|
|
+ class="text-subtitle1 text-bold q-pa-sm"
|
|
|
+ style="min-width: 40px; justify-content: center"
|
|
|
+ >
|
|
|
+ {{ feriado.dia }}
|
|
|
+ </q-badge>
|
|
|
+ <div class="text-caption q-mt-xs text-center">{{ feriado.nome }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </q-card-section>
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { onMounted, ref, watch } from "vue";
|
|
|
-import { useI18n } from "vue-i18n";
|
|
|
+import { ref } from "vue";
|
|
|
+import { Bar, Doughnut } from "vue-chartjs";
|
|
|
+import {
|
|
|
+ Chart as ChartJS,
|
|
|
+ Title,
|
|
|
+ Tooltip,
|
|
|
+ Legend,
|
|
|
+ BarElement,
|
|
|
+ CategoryScale,
|
|
|
+ LinearScale,
|
|
|
+ ArcElement,
|
|
|
+} from "chart.js";
|
|
|
+import ChartDataLabels from "chartjs-plugin-datalabels";
|
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
|
|
|
|
-const { t } = useI18n();
|
|
|
-
|
|
|
-const isLoading = ref(true);
|
|
|
-const defaultPeriod = ref("month");
|
|
|
-const defaultEventId = ref(1);
|
|
|
-
|
|
|
-const ordersChart = ref({});
|
|
|
-const participantsChart = ref({});
|
|
|
-const paymentsChart = ref({});
|
|
|
-const ticketsSoldChart = ref({});
|
|
|
-const eventTicketsByTypeChart = ref({});
|
|
|
-const eventParticipantsByCNPJAndCPF = ref({});
|
|
|
-const salesOverTimeLineChart = ref({});
|
|
|
-const eventSourcePieChart = ref({});
|
|
|
-
|
|
|
-const generateMockData = () => {
|
|
|
- const createMiniChartData = (currentTotal, percentage) => ({
|
|
|
- current_total: currentTotal,
|
|
|
- percentage_change: percentage,
|
|
|
- trend_data: Array.from({ length: 10 }, () =>
|
|
|
- Math.floor(Math.random() * 100),
|
|
|
- ),
|
|
|
- });
|
|
|
-
|
|
|
- const barChartDataRaw = [
|
|
|
- {
|
|
|
- label: t("dashboard.charts.tickets_by_type.labels.vip"),
|
|
|
- value: Math.floor(Math.random() * 300),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("dashboard.charts.tickets_by_type.labels.track"),
|
|
|
- value: Math.floor(Math.random() * 800),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("dashboard.charts.tickets_by_type.labels.box"),
|
|
|
- value: Math.floor(Math.random() * 400),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("dashboard.charts.tickets_by_type.labels.courtesy"),
|
|
|
- value: Math.floor(Math.random() * 50),
|
|
|
- },
|
|
|
- ];
|
|
|
+ChartJS.register(
|
|
|
+ Title,
|
|
|
+ Tooltip,
|
|
|
+ Legend,
|
|
|
+ BarElement,
|
|
|
+ CategoryScale,
|
|
|
+ LinearScale,
|
|
|
+ ArcElement,
|
|
|
+);
|
|
|
|
|
|
- const doughnutDataRaw = [
|
|
|
+// ── Faturamento Serviço / Materiais ───────────────────────────────────────────
|
|
|
+const faturamentoData = ref({
|
|
|
+ labels: ["17/02", "18/02", "19/02", "20/02", "21/02", "22/02", "23/02", "24/02", "25/02", "26/02", "27/02", "28/02"],
|
|
|
+ datasets: [
|
|
|
{
|
|
|
- label: t("common.terms.cpf"),
|
|
|
- value: Math.floor(Math.random() * 900 + 100),
|
|
|
+ label: "Serviços",
|
|
|
+ data: [120, 185, 95, 210, 155, 200, 170, 130, 195, 160, 145, 180],
|
|
|
+ backgroundColor: "rgba(99, 102, 241, 0.75)",
|
|
|
+ borderColor: "rgba(99, 102, 241, 1)",
|
|
|
+ borderWidth: 1,
|
|
|
},
|
|
|
{
|
|
|
- label: t("common.terms.cnpj"),
|
|
|
- value: Math.floor(Math.random() * 100 + 10),
|
|
|
+ label: "Materiais",
|
|
|
+ data: [75, 115, 60, 140, 95, 125, 105, 85, 135, 100, 90, 115],
|
|
|
+ backgroundColor: "rgba(236, 72, 153, 0.75)",
|
|
|
+ borderColor: "rgba(236, 72, 153, 1)",
|
|
|
+ borderWidth: 1,
|
|
|
},
|
|
|
- ];
|
|
|
- const doughnutTotal = doughnutDataRaw.reduce(
|
|
|
- (sum, item) => sum + item.value,
|
|
|
- 0,
|
|
|
- );
|
|
|
+ ],
|
|
|
+});
|
|
|
|
|
|
- const lineChartDataRaw = [
|
|
|
- {
|
|
|
- label: t("common.months.january"),
|
|
|
- value: Math.floor(1200 + Math.random() * 500),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("common.months.february"),
|
|
|
- value: Math.floor(1900 + Math.random() * 500),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("common.months.march"),
|
|
|
- value: Math.floor(3000 + Math.random() * 500),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("common.months.april"),
|
|
|
- value: Math.floor(5000 + Math.random() * 500),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("common.months.may"),
|
|
|
- value: Math.floor(2300 + Math.random() * 500),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("common.months.june"),
|
|
|
- value: Math.floor(3200 + Math.random() * 500),
|
|
|
- },
|
|
|
- ];
|
|
|
+const faturamentoOptions = ref({
|
|
|
+ responsive: true,
|
|
|
+ maintainAspectRatio: false,
|
|
|
+ plugins: {
|
|
|
+ legend: { display: true, position: "top", labels: { font: { size: 11 } } },
|
|
|
+ tooltip: { mode: "index", intersect: false },
|
|
|
+ datalabels: { display: false },
|
|
|
+ },
|
|
|
+ scales: {
|
|
|
+ x: { ticks: { font: { size: 9 } }, grid: { display: false } },
|
|
|
+ y: { ticks: { font: { size: 10 } }, suggestedMin: 0 },
|
|
|
+ },
|
|
|
+});
|
|
|
|
|
|
- const pieDataRaw = [
|
|
|
+// ── Contratos Ativos (gauge) ──────────────────────────────────────────────────
|
|
|
+const gaugeData = ref({
|
|
|
+ datasets: [
|
|
|
{
|
|
|
- label: t("dashboard.charts.registration_source.sources.instagram"),
|
|
|
- value: Math.floor(450 + Math.random() * 50),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("dashboard.charts.registration_source.sources.facebook"),
|
|
|
- value: Math.floor(250 + Math.random() * 50),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("dashboard.charts.registration_source.sources.google"),
|
|
|
- value: Math.floor(180 + Math.random() * 50),
|
|
|
- },
|
|
|
- {
|
|
|
- label: t("dashboard.charts.registration_source.sources.referral"),
|
|
|
- value: Math.floor(120 + Math.random() * 50),
|
|
|
- },
|
|
|
- ];
|
|
|
- const pieTotal = pieDataRaw.reduce((sum, item) => sum + item.value, 0);
|
|
|
-
|
|
|
- return {
|
|
|
- payments: createMiniChartData(
|
|
|
- (Math.random() * 20000 + 5000).toFixed(2),
|
|
|
- (Math.random() * 20 - 5).toFixed(2),
|
|
|
- ),
|
|
|
- orders: createMiniChartData(
|
|
|
- Math.floor(Math.random() * 500 + 50),
|
|
|
- (Math.random() * 15 - 5).toFixed(2),
|
|
|
- ),
|
|
|
- tickets_sold: createMiniChartData(
|
|
|
- Math.floor(Math.random() * 1500 + 200),
|
|
|
- (Math.random() * 25 - 5).toFixed(2),
|
|
|
- ),
|
|
|
- participants: createMiniChartData(
|
|
|
- Math.floor(Math.random() * 1000 + 100),
|
|
|
- (Math.random() * 10 - 5).toFixed(2),
|
|
|
- ),
|
|
|
- barData: {
|
|
|
- chart_data: barChartDataRaw,
|
|
|
+ backgroundColor: [
|
|
|
+ "#00a550", "#4dbb7e", "#9ad2ad", "#cce156",
|
|
|
+ "#fff100", "#ffbe00", "#ff8c00", "#FC3D23", "#D01616", "#8A0000",
|
|
|
+ ],
|
|
|
+ data: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
|
|
+ needleValue: 7,
|
|
|
+ borderColor: "transparent",
|
|
|
},
|
|
|
- doughnutData: {
|
|
|
- chart_data: doughnutDataRaw,
|
|
|
- current_total: doughnutTotal,
|
|
|
- },
|
|
|
- lineData: {
|
|
|
- chart_data: lineChartDataRaw,
|
|
|
- },
|
|
|
- pieData: {
|
|
|
- chart_data: pieDataRaw,
|
|
|
- current_total: pieTotal,
|
|
|
- },
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-const updateDashboardData = async () => {
|
|
|
- isLoading.value = true;
|
|
|
- setTimeout(() => {
|
|
|
- const mockData = generateMockData();
|
|
|
-
|
|
|
- ordersChart.value = mockData.orders;
|
|
|
- participantsChart.value = mockData.participants;
|
|
|
- paymentsChart.value = mockData.payments;
|
|
|
- ticketsSoldChart.value = mockData.tickets_sold;
|
|
|
+ ],
|
|
|
+});
|
|
|
|
|
|
- eventTicketsByTypeChart.value = mockData.barData;
|
|
|
- eventParticipantsByCNPJAndCPF.value = mockData.doughnutData;
|
|
|
- salesOverTimeLineChart.value = mockData.lineData;
|
|
|
- eventSourcePieChart.value = mockData.pieData;
|
|
|
+const gaugeOptions = ref({
|
|
|
+ rotation: 270,
|
|
|
+ circumference: 180,
|
|
|
+ cutout: "55%",
|
|
|
+ responsive: true,
|
|
|
+ maintainAspectRatio: false,
|
|
|
+ plugins: {
|
|
|
+ tooltip: { enabled: false },
|
|
|
+ legend: { display: false },
|
|
|
+ datalabels: { display: false },
|
|
|
+ },
|
|
|
+});
|
|
|
|
|
|
- isLoading.value = false;
|
|
|
- }, 500);
|
|
|
+const gaugeNeedlePlugin = {
|
|
|
+ id: "gaugeNeedle",
|
|
|
+ afterDatasetsDraw(chart) {
|
|
|
+ const { ctx, data } = chart;
|
|
|
+ ctx.save();
|
|
|
+ const needleValue = data.datasets[0].needleValue;
|
|
|
+ const meta = chart.getDatasetMeta(0).data[0];
|
|
|
+ const xCenter = meta.x;
|
|
|
+ const yCenter = meta.y;
|
|
|
+ const outerRadius = meta.outerRadius - 20;
|
|
|
+ const circumference =
|
|
|
+ (meta.circumference / Math.PI / data.datasets[0].data[0]) * needleValue;
|
|
|
+ const angle = Math.PI;
|
|
|
+ ctx.translate(xCenter, yCenter);
|
|
|
+ ctx.rotate(angle * (circumference + 1.5));
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.strokeStyle = "grey";
|
|
|
+ ctx.fillStyle = "grey";
|
|
|
+ ctx.moveTo(-3, 0);
|
|
|
+ ctx.lineTo(0, -outerRadius);
|
|
|
+ ctx.lineTo(3, 0);
|
|
|
+ ctx.stroke();
|
|
|
+ ctx.fill();
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.arc(0, 0, 6, 0, 2 * Math.PI);
|
|
|
+ ctx.fillStyle = "grey";
|
|
|
+ ctx.fill();
|
|
|
+ ctx.restore();
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
-watch([defaultPeriod, defaultEventId], async () => {
|
|
|
- await updateDashboardData();
|
|
|
+// ── Matrículas por Período ────────────────────────────────────────────────────
|
|
|
+const matriculasData = ref({
|
|
|
+ labels: ["JAN", "FEV", "MAR", "ABR", "MAI", "JUN"],
|
|
|
+ datasets: [
|
|
|
+ {
|
|
|
+ label: "Matrículas",
|
|
|
+ data: [120, 200, 150, 80, 70, 110],
|
|
|
+ backgroundColor: ["#2196F3", "#F44336", "#9C27B0", "#FFC107", "#212121", "#009688"],
|
|
|
+ borderColor: ["#2196F3", "#F44336", "#9C27B0", "#FFC107", "#212121", "#009688"],
|
|
|
+ borderWidth: 1,
|
|
|
+ borderRadius: 2,
|
|
|
+ },
|
|
|
+ ],
|
|
|
});
|
|
|
|
|
|
-onMounted(async () => {
|
|
|
- await updateDashboardData();
|
|
|
+const matriculasOptions = ref({
|
|
|
+ responsive: true,
|
|
|
+ maintainAspectRatio: false,
|
|
|
+ plugins: {
|
|
|
+ legend: { display: false },
|
|
|
+ datalabels: {
|
|
|
+ anchor: "end",
|
|
|
+ align: "top",
|
|
|
+ color: "#666",
|
|
|
+ font: { size: 11, weight: "bold" },
|
|
|
+ formatter: (v) => v,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ scales: {
|
|
|
+ x: { ticks: { font: { size: 11 } }, grid: { display: false } },
|
|
|
+ y: { display: false, suggestedMin: 0, suggestedMax: 230 },
|
|
|
+ },
|
|
|
});
|
|
|
+
|
|
|
+// ── Aniversariantes do Mês ────────────────────────────────────────────────────
|
|
|
+const aniversariantes = ref([
|
|
|
+ { nome: "Heloisa Faria", color: "orange" },
|
|
|
+ { nome: "Juliana Costa", color: "green" },
|
|
|
+ { nome: "Juliana Costa", color: "green" },
|
|
|
+ { nome: "Fernando Almeida", color: "blue" },
|
|
|
+ { nome: "Lucas Pereira", color: "purple" },
|
|
|
+ { nome: "Sofia Martins", color: "teal" },
|
|
|
+]);
|
|
|
+
|
|
|
+// ── Feriados do mês ───────────────────────────────────────────────────────────
|
|
|
+const feriados = ref([
|
|
|
+ { dia: 17, nome: "Carnaval", color: "amber" },
|
|
|
+ { dia: 17, nome: "Carnaval", color: "amber" },
|
|
|
+ { dia: 17, nome: "Carnaval", color: "amber" },
|
|
|
+]);
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.gap {
|
|
|
- gap: 16px;
|
|
|
+.gauge-label {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 28%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ text-align: center;
|
|
|
+ pointer-events: none;
|
|
|
}
|
|
|
</style>
|