|
@@ -1,167 +1,243 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div>
|
|
<div>
|
|
|
- <DefaultHeaderPage>
|
|
|
|
|
|
|
+ <DefaultHeaderPage show-filter-icon class="q-pa-sm">
|
|
|
<template #after>
|
|
<template #after>
|
|
|
- <q-btn
|
|
|
|
|
- outline
|
|
|
|
|
- icon="mdi-calendar"
|
|
|
|
|
- color="primary"
|
|
|
|
|
- @click="showFilter"
|
|
|
|
|
- />
|
|
|
|
|
- </template>
|
|
|
|
|
- </DefaultHeaderPage>
|
|
|
|
|
- <q-expansion-item
|
|
|
|
|
- v-model="filter"
|
|
|
|
|
- dense
|
|
|
|
|
- hide-expand-icon
|
|
|
|
|
- class="remove-header-expansion-item"
|
|
|
|
|
- >
|
|
|
|
|
- <DatePeriodSelector
|
|
|
|
|
- v-model:selected-period="defaultPeriod"
|
|
|
|
|
- v-model:selected-event-id="defaultEventId"
|
|
|
|
|
- class="q-pa-sm"
|
|
|
|
|
- />
|
|
|
|
|
- </q-expansion-item>
|
|
|
|
|
-
|
|
|
|
|
- <div v-if="!isLoading" class="column gap q-pa-sm">
|
|
|
|
|
- <div class="flex full-width gap">
|
|
|
|
|
- <div class="flex flex-grow gap">
|
|
|
|
|
- <CardIconMiniChart
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
- :title="t('dashboard.cards.total_earnings')"
|
|
|
|
|
- :icon="'mdi-currency-usd'"
|
|
|
|
|
- :number-porcent="paymentsChart.percentage_change"
|
|
|
|
|
- :number-card="
|
|
|
|
|
- t('dashboard.currency_format', {
|
|
|
|
|
- value: paymentsChart.current_total,
|
|
|
|
|
- })
|
|
|
|
|
- "
|
|
|
|
|
|
|
+ <div class="flex items-center no-wrap" style="gap: 12px">
|
|
|
|
|
+ <q-select
|
|
|
|
|
+ v-if="$q.screen.gt.xs"
|
|
|
|
|
+ v-model="selectedUnit"
|
|
|
|
|
+ dense
|
|
|
|
|
+ :options="[]"
|
|
|
|
|
+ label="Unidade"
|
|
|
|
|
+ style="width: 250px; flex-shrink: 0"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ label-color="secondary"
|
|
|
|
|
+ hide-dropdown-icon
|
|
|
>
|
|
>
|
|
|
- <template #chart>
|
|
|
|
|
- <MiniLineChart
|
|
|
|
|
- :data="paymentsChart.trend_data"
|
|
|
|
|
- fill-color="rgba(0, 0, 0, 0)"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <template #append>
|
|
|
|
|
+ <q-icon name="mdi-map-marker-outline" color="secondary" />
|
|
|
</template>
|
|
</template>
|
|
|
- </CardIconMiniChart>
|
|
|
|
|
- <CardIconMiniChart
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
- :title="t('orders.plural')"
|
|
|
|
|
- :icon="'mdi-package-variant'"
|
|
|
|
|
- :number-porcent="ordersChart.percentage_change"
|
|
|
|
|
- :number-card="ordersChart.current_total"
|
|
|
|
|
- >
|
|
|
|
|
- <template #chart>
|
|
|
|
|
- <MiniBarChart
|
|
|
|
|
- :data="ordersChart.trend_data"
|
|
|
|
|
- fill-color="rgba(0, 0, 0, 0)"
|
|
|
|
|
- />
|
|
|
|
|
- </template>
|
|
|
|
|
- </CardIconMiniChart>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex flex-grow gap">
|
|
|
|
|
- <CardIconMiniChart
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
- :title="t('dashboard.cards.tickets_sold')"
|
|
|
|
|
- :icon="'mdi-ticket-outline'"
|
|
|
|
|
- :number-porcent="ticketsSoldChart.percentage_change"
|
|
|
|
|
- :number-card="ticketsSoldChart.current_total"
|
|
|
|
|
|
|
+ </q-select>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="flex items-center no-wrap q-gutter-x-md q-px-sm q-ml-md"
|
|
|
|
|
+ style="flex-shrink: 0"
|
|
|
>
|
|
>
|
|
|
- <template #chart>
|
|
|
|
|
- <MiniLineChart
|
|
|
|
|
- :data="ticketsSoldChart.trend_data"
|
|
|
|
|
- fill-color="rgba(0, 0, 0, 0)"
|
|
|
|
|
- />
|
|
|
|
|
- </template>
|
|
|
|
|
- </CardIconMiniChart>
|
|
|
|
|
- <CardIconMiniChart
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
- :title="t('dashboard.cards.registrations')"
|
|
|
|
|
- :icon="'mdi-account-group-outline'"
|
|
|
|
|
- :number-porcent="participantsChart.percentage_change"
|
|
|
|
|
- :number-card="participantsChart.current_total"
|
|
|
|
|
|
|
+ <q-img src="icons/user-icon.jpg" class="avatar-circle" />
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="$q.screen.gt.xs"
|
|
|
|
|
+ class="column q-gutter-y-none"
|
|
|
|
|
+ style="white-space: nowrap"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="text-body2 text-center">Ana Laura</span>
|
|
|
|
|
+ <span
|
|
|
|
|
+ v-if="$q.screen.gt.sm"
|
|
|
|
|
+ class="text-overline text-center"
|
|
|
|
|
+ style="line-height: 1rem; font-weight: 400"
|
|
|
|
|
+ >Gerente</span
|
|
|
|
|
+ >
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <template v-if="$q.screen.gt.sm">
|
|
|
|
|
+ <q-separator
|
|
|
|
|
+ vertical
|
|
|
|
|
+ style="height: 36px; width: 2px; flex-shrink: 0"
|
|
|
|
|
+ color="dark"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="column"
|
|
|
|
|
+ style="line-height: 1.2; white-space: nowrap; flex-shrink: 0"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="text-caption text-grey-6 text-primary text-center"
|
|
|
|
|
+ >Ultimo acesso</span
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="text-caption text-primary text-center"
|
|
|
|
|
+ >16/02/2026, 14:16</span
|
|
|
|
|
+ >
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="flex items-center no-wrap"
|
|
|
|
|
+ style="gap: 2px; flex-shrink: 0"
|
|
|
>
|
|
>
|
|
|
- <template #chart>
|
|
|
|
|
- <MiniBarChart
|
|
|
|
|
- :data="participantsChart.trend_data"
|
|
|
|
|
- fill-color="rgba(0, 0, 0, 0)"
|
|
|
|
|
- />
|
|
|
|
|
- </template>
|
|
|
|
|
- </CardIconMiniChart>
|
|
|
|
|
|
|
+ <q-btn flat round dense icon="mdi-bell-badge" color="secondary" />
|
|
|
|
|
+ <q-btn flat round dense icon="mdi-account" color="secondary" />
|
|
|
|
|
+ <q-btn flat round dense icon="mdi-cog-outline" color="secondary" />
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </DefaultHeaderPage>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="q-pa-sm">
|
|
|
|
|
+ <div class="filter-row">
|
|
|
|
|
+ <q-select
|
|
|
|
|
+ v-model="selectedPeriod"
|
|
|
|
|
+ :options="periodOptions"
|
|
|
|
|
+ option-value="value"
|
|
|
|
|
+ option-label="label"
|
|
|
|
|
+ emit-value
|
|
|
|
|
+ map-options
|
|
|
|
|
+ dense
|
|
|
|
|
+ label="Selecione o Período"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ class="filter-item"
|
|
|
|
|
+ hide-dropdown-icon
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #append>
|
|
|
|
|
+ <q-icon name="mdi-chevron-down" color="secondary" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </q-select>
|
|
|
|
|
|
|
|
- <div class="flex full-width gap">
|
|
|
|
|
- <div class="flex flex-grow">
|
|
|
|
|
- <CardIconChart
|
|
|
|
|
- :title="t('dashboard.charts.tickets_by_type.title')"
|
|
|
|
|
- :icon="'mdi-ticket-account'"
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
|
|
+ <template v-if="selectedPeriod === 'custom'">
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ v-model="startDate"
|
|
|
|
|
+ dense
|
|
|
|
|
+ label="Data Inicial"
|
|
|
|
|
+ mask="##/##/####"
|
|
|
|
|
+ placeholder="DD/MM/AAAA"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ class="filter-item"
|
|
|
>
|
|
>
|
|
|
- <template #chart>
|
|
|
|
|
- <BarChart
|
|
|
|
|
- :data="eventTicketsByTypeChart"
|
|
|
|
|
- :data-set-label="t('events.tickets.plural')"
|
|
|
|
|
- :label-x="t('events.tickets.types_singular')"
|
|
|
|
|
- :label-y="t('common.terms.quantity')"
|
|
|
|
|
- :show-legend="true"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <template #append>
|
|
|
|
|
+ <q-icon
|
|
|
|
|
+ name="mdi-calendar"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ class="cursor-pointer"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-popup-proxy
|
|
|
|
|
+ cover
|
|
|
|
|
+ transition-show="scale"
|
|
|
|
|
+ transition-hide="scale"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-date
|
|
|
|
|
+ v-model="startDate"
|
|
|
|
|
+ mask="DD/MM/YYYY"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="row items-center justify-end">
|
|
|
|
|
+ <q-btn v-close-popup label="OK" color="secondary" flat />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </q-date>
|
|
|
|
|
+ </q-popup-proxy>
|
|
|
|
|
+ </q-icon>
|
|
|
</template>
|
|
</template>
|
|
|
- </CardIconChart>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex flex-grow">
|
|
|
|
|
- <CardIconChart
|
|
|
|
|
- :title="t('dashboard.charts.participants_by_document.title')"
|
|
|
|
|
- :icon="'mdi-badge-account'"
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
|
|
+ </q-input>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ v-model="endDate"
|
|
|
|
|
+ dense
|
|
|
|
|
+ label="Data Final"
|
|
|
|
|
+ mask="##/##/####"
|
|
|
|
|
+ placeholder="DD/MM/AAAA"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ class="filter-item"
|
|
|
>
|
|
>
|
|
|
- <template #chart>
|
|
|
|
|
- <DoughnutChart
|
|
|
|
|
- :data="eventParticipantsByCNPJAndCPF"
|
|
|
|
|
- :data-set-label="t('events.attendance.participant_plural')"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <template #append>
|
|
|
|
|
+ <q-icon
|
|
|
|
|
+ name="mdi-calendar"
|
|
|
|
|
+ color="secondary"
|
|
|
|
|
+ class="cursor-pointer"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-popup-proxy
|
|
|
|
|
+ cover
|
|
|
|
|
+ transition-show="scale"
|
|
|
|
|
+ transition-hide="scale"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-date v-model="endDate" mask="DD/MM/YYYY" color="secondary">
|
|
|
|
|
+ <div class="row items-center justify-end">
|
|
|
|
|
+ <q-btn v-close-popup label="OK" color="secondary" flat />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </q-date>
|
|
|
|
|
+ </q-popup-proxy>
|
|
|
|
|
+ </q-icon>
|
|
|
</template>
|
|
</template>
|
|
|
- </CardIconChart>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ </q-input>
|
|
|
|
|
+ </template>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- <div class="flex full-width gap">
|
|
|
|
|
- <div class="flex flex-grow">
|
|
|
|
|
- <CardIconChart
|
|
|
|
|
- :title="t('dashboard.charts.sales_over_time.title')"
|
|
|
|
|
- :icon="'mdi-chart-line'"
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
- >
|
|
|
|
|
- <template #chart>
|
|
|
|
|
- <LineChart
|
|
|
|
|
- :data="salesOverTimeLineChart"
|
|
|
|
|
- :data-set-label="t('ui.navigation.sales')"
|
|
|
|
|
- :label-x="t('common.terms.month')"
|
|
|
|
|
- :label-y="
|
|
|
|
|
- t('dashboard.charts.sales_over_time.y_label', {
|
|
|
|
|
- currency: 'R$',
|
|
|
|
|
- })
|
|
|
|
|
- "
|
|
|
|
|
- />
|
|
|
|
|
- </template>
|
|
|
|
|
- </CardIconChart>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex flex-grow">
|
|
|
|
|
- <CardIconChart
|
|
|
|
|
- :title="t('dashboard.charts.registration_source.title')"
|
|
|
|
|
- :icon="'mdi-chart-pie'"
|
|
|
|
|
- class="flex-grow"
|
|
|
|
|
- >
|
|
|
|
|
- <template #chart>
|
|
|
|
|
- <PieChart
|
|
|
|
|
- :data="eventSourcePieChart"
|
|
|
|
|
- :data-set-label="
|
|
|
|
|
- t('dashboard.charts.registration_source.source')
|
|
|
|
|
- "
|
|
|
|
|
- />
|
|
|
|
|
- </template>
|
|
|
|
|
- </CardIconChart>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div v-if="!isLoading" class="column gap q-pa-sm">
|
|
|
|
|
+ <div class="stat-cards-row">
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Total alunos (contratos ativos)"
|
|
|
|
|
+ icon="mdi-account-multiple"
|
|
|
|
|
+ value="4.527"
|
|
|
|
|
+ badge="3.200 ativos"
|
|
|
|
|
+ />
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Contratos Congelados"
|
|
|
|
|
+ icon="mdi-snowflake"
|
|
|
|
|
+ value="57"
|
|
|
|
|
+ subtitle="É hora de incentivar nossos alunos"
|
|
|
|
|
+ />
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Contratos Cancelados"
|
|
|
|
|
+ icon="mdi-cancel"
|
|
|
|
|
+ value="57"
|
|
|
|
|
+ subtitle="É hora de incentivar nossos alunos"
|
|
|
|
|
+ />
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Receita Geral"
|
|
|
|
|
+ icon="mdi-currency-usd"
|
|
|
|
|
+ value="R$ 51.548,80"
|
|
|
|
|
+ subtitle="0 pagamentos pendentes"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="charts-row">
|
|
|
|
|
+ <DashboardChartCard title="Faturamento Serviço / Materiais">
|
|
|
|
|
+ <GroupedBarChart
|
|
|
|
|
+ :labels="faturamentoChart.labels"
|
|
|
|
|
+ :datasets="faturamentoChart.datasets"
|
|
|
|
|
+ label-y="R$"
|
|
|
|
|
+ :tick-formatter="formatCurrencyTick"
|
|
|
|
|
+ :tooltip-formatter="formatCurrencyTooltip"
|
|
|
|
|
+ class="full-width full-height"
|
|
|
|
|
+ />
|
|
|
|
|
+ </DashboardChartCard>
|
|
|
|
|
+
|
|
|
|
|
+ <DashboardChartCard title="Matrículas por Período">
|
|
|
|
|
+ <GroupedBarChart
|
|
|
|
|
+ :labels="matriculasChart.labels"
|
|
|
|
|
+ :datasets="matriculasChart.datasets"
|
|
|
|
|
+ :bar-radius="50"
|
|
|
|
|
+ :show-datalabels="true"
|
|
|
|
|
+ class="full-width full-height"
|
|
|
|
|
+ />
|
|
|
|
|
+ </DashboardChartCard>
|
|
|
|
|
+
|
|
|
|
|
+ <AniversariantesCard :people="aniversariantes" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="stat-cards-row">
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Frequência Média"
|
|
|
|
|
+ icon="mdi-account-multiple-outline"
|
|
|
|
|
+ value="87%"
|
|
|
|
|
+ badge="Alta"
|
|
|
|
|
+ badge-color="positive"
|
|
|
|
|
+ />
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Estoque Geral de Produtos"
|
|
|
|
|
+ icon="mdi-currency-usd"
|
|
|
|
|
+ value="56"
|
|
|
|
|
+ />
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Tarefas Pendentes"
|
|
|
|
|
+ icon="mdi-draw"
|
|
|
|
|
+ value="4"
|
|
|
|
|
+ subtitle="Não deixe para amanhã"
|
|
|
|
|
+ />
|
|
|
|
|
+ <DashboardStatCard
|
|
|
|
|
+ title="Tickets Abertos"
|
|
|
|
|
+ icon="mdi-calendar-outline"
|
|
|
|
|
+ value="2"
|
|
|
|
|
+ subtitle="Estável"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
@@ -172,43 +248,83 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { onMounted, ref, watch, defineAsyncComponent } from "vue";
|
|
|
|
|
|
|
+import { onMounted, ref, watch } from "vue";
|
|
|
import { useI18n } from "vue-i18n";
|
|
import { useI18n } from "vue-i18n";
|
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
|
-import DatePeriodSelector from "./components/DatePeriodSelector.vue";
|
|
|
|
|
-
|
|
|
|
|
-const MiniLineChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/mini/MiniLineChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const MiniBarChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/mini/MiniBarChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const CardIconMiniChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/CardIconMiniChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const CardIconChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/CardIconChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const BarChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/normal/BarChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const DoughnutChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/normal/DoughnutChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const LineChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/normal/LineChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
-const PieChart = defineAsyncComponent(
|
|
|
|
|
- () => import("src/components/charts/normal/PieChart.vue"),
|
|
|
|
|
-);
|
|
|
|
|
|
|
+import DashboardStatCard from "src/components/charts/DashboardStatCard.vue";
|
|
|
|
|
+import DashboardChartCard from "src/components/charts/DashboardChartCard.vue";
|
|
|
|
|
+import GroupedBarChart from "src/components/charts/normal/GroupedBarChart.vue";
|
|
|
|
|
+import AniversariantesCard from "src/components/charts/AniversariantesCard.vue";
|
|
|
|
|
|
|
|
const { t } = useI18n();
|
|
const { t } = useI18n();
|
|
|
|
|
|
|
|
const isLoading = ref(true);
|
|
const isLoading = ref(true);
|
|
|
-const filter = ref(false);
|
|
|
|
|
|
|
+const selectedUnit = ref(null);
|
|
|
const defaultPeriod = ref("month");
|
|
const defaultPeriod = ref("month");
|
|
|
const defaultEventId = ref(1);
|
|
const defaultEventId = ref(1);
|
|
|
|
|
|
|
|
|
|
+const selectedPeriod = ref("custom");
|
|
|
|
|
+const startDate = ref("");
|
|
|
|
|
+const endDate = ref("");
|
|
|
|
|
+
|
|
|
|
|
+const periodOptions = [
|
|
|
|
|
+ { label: "Hoje", value: "today" },
|
|
|
|
|
+ { label: "Esta semana", value: "week" },
|
|
|
|
|
+ { label: "Este mês", value: "month" },
|
|
|
|
|
+ { label: "Este ano", value: "year" },
|
|
|
|
|
+ { label: "Personalizado", value: "custom" },
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+// --- Aniversariantes do Mês (hardcoded) ---
|
|
|
|
|
+const aniversariantes = [
|
|
|
|
|
+ { day: 10, name: "Heloisa Faria" },
|
|
|
|
|
+ { day: 7, name: "Juliana Costa" },
|
|
|
|
|
+ { day: 24, name: "Fernando Almeida" },
|
|
|
|
|
+ { day: 28, name: "Patrícia Lima" },
|
|
|
|
|
+];
|
|
|
|
|
+// -------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+// --- Matrículas por Período (hardcoded) ---
|
|
|
|
|
+const matriculasChart = {
|
|
|
|
|
+ labels: ["JAN", "FEV", "MAR", "ABR", "MAI", "JUN"],
|
|
|
|
|
+ datasets: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "Matrículas",
|
|
|
|
|
+ data: [120, 200, 150, 80, 70, 110],
|
|
|
|
|
+ color: ["#3B82F6", "#EF4444", "#A855F7", "#374151", "#EAB308", "#06B6D4"],
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+};
|
|
|
|
|
+// ---------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+// --- Faturamento Serviço / Materiais (hardcoded) ---
|
|
|
|
|
+const faturamentoChart = {
|
|
|
|
|
+ labels: ["17/02", "20/02", "23/02", "26/02"],
|
|
|
|
|
+ datasets: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "Serviço",
|
|
|
|
|
+ data: [18500, 22300, 15800, 27600],
|
|
|
|
|
+ color: "#7C3AED",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: "Materiais",
|
|
|
|
|
+ data: [9200, 11400, 8700, 13100],
|
|
|
|
|
+ color: "#EC4899",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const formatCurrencyTick = (value) => {
|
|
|
|
|
+ if (value >= 1000) return `R$ ${(value / 1000).toFixed(0)}k`;
|
|
|
|
|
+ return `R$ ${value}`;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const formatCurrencyTooltip = (context) => {
|
|
|
|
|
+ const value = context.parsed.y;
|
|
|
|
|
+ return ` ${context.dataset.label}: R$ ${value.toLocaleString("pt-BR", { minimumFractionDigits: 2 })}`;
|
|
|
|
|
+};
|
|
|
|
|
+// ---------------------------------------------------
|
|
|
|
|
+
|
|
|
const ordersChart = ref({});
|
|
const ordersChart = ref({});
|
|
|
const participantsChart = ref({});
|
|
const participantsChart = ref({});
|
|
|
const paymentsChart = ref({});
|
|
const paymentsChart = ref({});
|
|
@@ -218,10 +334,6 @@ const eventParticipantsByCNPJAndCPF = ref({});
|
|
|
const salesOverTimeLineChart = ref({});
|
|
const salesOverTimeLineChart = ref({});
|
|
|
const eventSourcePieChart = ref({});
|
|
const eventSourcePieChart = ref({});
|
|
|
|
|
|
|
|
-const showFilter = () => {
|
|
|
|
|
- filter.value = !filter.value;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
const generateMockData = () => {
|
|
const generateMockData = () => {
|
|
|
const createMiniChartData = (currentTotal, percentage) => ({
|
|
const createMiniChartData = (currentTotal, percentage) => ({
|
|
|
current_total: currentTotal,
|
|
current_total: currentTotal,
|
|
@@ -378,4 +490,70 @@ onMounted(async () => {
|
|
|
.gap {
|
|
.gap {
|
|
|
gap: 16px;
|
|
gap: 16px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.avatar-circle {
|
|
|
|
|
+ width: 36px;
|
|
|
|
|
+ height: 36px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.stat-cards-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.stat-cards-row > * {
|
|
|
|
|
+ flex: 1 1 200px;
|
|
|
|
|
+ min-width: 180px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (max-width: 599px) {
|
|
|
|
|
+ .stat-cards-row > * {
|
|
|
|
|
+ flex: 1 1 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.charts-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.charts-row > * {
|
|
|
|
|
+ flex: 1 1 350px;
|
|
|
|
|
+ min-width: 280px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.charts-row > *:last-child {
|
|
|
|
|
+ flex: 0 1 240px;
|
|
|
|
|
+ min-width: 200px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (max-width: 599px) {
|
|
|
|
|
+ .charts-row > * {
|
|
|
|
|
+ flex: 1 1 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.filter-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.filter-item {
|
|
|
|
|
+ flex: 1 1 200px;
|
|
|
|
|
+ min-width: 180px;
|
|
|
|
|
+ max-width: 300px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@media (max-width: 599px) {
|
|
|
|
|
+ .filter-item {
|
|
|
|
|
+ flex: 1 1 100%;
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|