Просмотр исходного кода

feat(dashboard): enhance getFranchisorDashboard to accept period parameters; update DashboardPage to handle date selection and display unit metrics

ebagabee 1 неделя назад
Родитель
Сommit
e1a16776fe
2 измененных файлов с 81 добавлено и 5 удалено
  1. 6 2
      src/api/dashboard.js
  2. 75 3
      src/pages/dashboard/DashboardPage.vue

+ 6 - 2
src/api/dashboard.js

@@ -1,8 +1,12 @@
 import api from "src/api";
 
-export const getFranchisorDashboard = async (unitIds = []) => {
+export const getFranchisorDashboard = async (unitIds = [], period = {}) => {
   const { data } = await api.get("/franchisor-dashboard/overview", {
-    params: unitIds.length ? { unit_ids: unitIds } : {},
+    params: {
+      ...(unitIds.length ? { unit_ids: unitIds } : {}),
+      ...(period.startDate ? { start_date: period.startDate } : {}),
+      ...(period.endDate ? { end_date: period.endDate } : {}),
+    },
   });
   return data.payload;
 };

+ 75 - 3
src/pages/dashboard/DashboardPage.vue

@@ -45,6 +45,7 @@
           <template v-if="selectedPeriod === 'custom'">
             <DefaultInputDatePicker
               v-model="startDate"
+              v-model:untreated-date="startDateIso"
               dense
               label="Data Inicial"
               color="secondary"
@@ -53,6 +54,7 @@
 
             <DefaultInputDatePicker
               v-model="endDate"
+              v-model:untreated-date="endDateIso"
               dense
               label="Data Final"
               color="secondary"
@@ -141,6 +143,27 @@
         />
       </div>
 
+      <div class="stat-cards-row">
+        <DashboardStatCard
+          title="Total de Unidades"
+          icon="mdi-store-outline"
+          :value="unitsSummary.total"
+          subtitle="Unidades cadastradas"
+        />
+        <DashboardStatCard
+          title="Faturamento das Unidades"
+          icon="mdi-cash-multiple"
+          :value="formatToBRLCurrency(unitsSummary.revenue)"
+          :subtitle="revenuePeriodLabel"
+        />
+        <DashboardStatCard
+          title="Contratos das Unidades"
+          icon="mdi-file-document-check-outline"
+          :value="`${unitsSummary.active_contracts} vigentes`"
+          :subtitle="`${unitsSummary.without_active_contract} sem contrato vigente`"
+        />
+      </div>
+
       <div class="charts-row">
         <DashboardChartCard title="Faturamento Serviço / Materiais">
           <GroupedBarChart
@@ -217,15 +240,23 @@ const openTickets      = ref(0);
 const pendingTasks     = ref(0);
 const productStock     = ref(0);
 const generalRevenue   = ref({ value: 0, pending_count: 0 });
+const unitsSummary     = ref({
+  total: 0,
+  revenue: 0,
+  active_contracts: 0,
+  without_active_contract: 0,
+});
 const birthdays        = ref([]);
 
 // ─── Filter state ────────────────────────────────────────────
 const showFilter    = ref(false);
 const selectedUnit  = ref(null);   // { label, value } | null
 const selectedGroup = ref(null);   // { label, value, unit_ids } | null
-const selectedPeriod = ref("custom");
+const selectedPeriod = ref("month");
 const startDate     = ref("");
 const endDate       = ref("");
+const startDateIso  = ref("");
+const endDateIso    = ref("");
 
 const periodOptions = [
   { label: "Hoje",         value: "today"  },
@@ -235,6 +266,45 @@ const periodOptions = [
   { label: "Personalizado", value: "custom" },
 ];
 
+const toIsoDate = (date) => {
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, "0");
+  const day = String(date.getDate()).padStart(2, "0");
+  return `${year}-${month}-${day}`;
+};
+
+const revenuePeriod = computed(() => {
+  const now = new Date();
+  let start;
+  let end = now;
+
+  if (selectedPeriod.value === "today") {
+    start = now;
+  } else if (selectedPeriod.value === "week") {
+    start = new Date(now);
+    const day = start.getDay() || 7;
+    start.setDate(start.getDate() - day + 1);
+  } else if (selectedPeriod.value === "year") {
+    start = new Date(now.getFullYear(), 0, 1);
+  } else if (selectedPeriod.value === "custom") {
+    if (!startDateIso.value || !endDateIso.value) return {};
+    return { startDate: startDateIso.value, endDate: endDateIso.value };
+  } else {
+    start = new Date(now.getFullYear(), now.getMonth(), 1);
+  }
+
+  return { startDate: toIsoDate(start), endDate: toIsoDate(end) };
+});
+
+const revenuePeriodLabel = computed(() => {
+  if (!revenuePeriod.value.startDate) return "Mês atual";
+  const format = (value) => value.split("-").reverse().join("/");
+  if (revenuePeriod.value.startDate === revenuePeriod.value.endDate) {
+    return `Faturamento em ${format(revenuePeriod.value.startDate)}`;
+  }
+  return `De ${format(revenuePeriod.value.startDate)} a ${format(revenuePeriod.value.endDate)}`;
+});
+
 /**
  * Array of unit IDs to use as filter.
  * - Group selected  → all unit IDs in that group
@@ -310,7 +380,7 @@ const fetchMetrics = async () => {
   const [studentSummary, contractSummary, dashboard] = await Promise.all([
     getStudentSummaryFranchisor(ids),
     getFranchisorContractSummary(ids),
-    getFranchisorDashboard(ids),
+    getFranchisorDashboard(ids, revenuePeriod.value),
   ]);
 
   totalStudents.value      = studentSummary.total;
@@ -322,6 +392,7 @@ const fetchMetrics = async () => {
   pendingTasks.value   = dashboard.pending_tasks ?? 0;
   productStock.value   = dashboard.product_stock ?? 0;
   generalRevenue.value = dashboard.general_revenue ?? { value: 0, pending_count: 0 };
+  unitsSummary.value   = dashboard.units_summary ?? unitsSummary.value;
   birthdays.value      = dashboard.birthdays ?? [];
 
   matriculasChart.value = {
@@ -337,7 +408,8 @@ const fetchMetrics = async () => {
 };
 
 // Re-fetch whenever unit/group filter changes
-watch(activeUnitIds, async () => {
+watch([activeUnitIds, selectedPeriod, startDateIso, endDateIso], async () => {
+  if (selectedPeriod.value === "custom" && (!startDateIso.value || !endDateIso.value)) return;
   isLoading.value = true;
   try {
     await fetchMetrics();