Files
clinicpro/docs/phase2_taskes/task-16-smart-dashboard/architecture.md
T

3.0 KiB

معماری — تسک ۱۶: داشبورد هوشمند

فایل‌هایی که تغییر می‌کنند

src/Dashboard/Controller/DashboardController.php   ← اضافه کردن from/to به query + فیلدهای جدید
src/Admin/Controller/AdminApiController.php         ← متد dashboardCharts() → محدود به بازه زمانی
assets/admin/pages/DashboardPage.tsx               ← date range selector + نمودارها

تغییر Backend

DashboardController — اضافه کردن from/to

#[Route('/api/v1/dashboard/clinic', methods: ['GET'])]
public function clinic(Request $request): JsonResponse
{
    $from = (int) $request->query->get('from', strtotime('-30 days'));
    $to   = (int) $request->query->get('to', time());

    // query موجود را محدود به بازه می‌کنیم:
    // WHERE created_at BETWEEN :from AND :to

    // فیلدهای جدید:
    $smsBalance     = $this->smsWalletRepo->getBalance($entityType, $entityId);
    $uniquePatients = $this->patientRecordRepo->countUnique($entityType, $entityId, $from, $to);
    $revenue        = $this->patientSessionRepo->sumRevenue($entityType, $entityId, $from, $to);

    return $this->success([
        // ... فیلدهای موجود ...
        'sms_wallet_balance'   => $smsBalance,
        'unique_patients_count' => $uniquePatients,
        'revenue_period_rials'  => $revenue,
    ]);
}

AdminApiController — dashboardCharts با بازه زمانی

#[Route('/api/v1/admin/dashboard/charts', methods: ['GET'])]
public function dashboardCharts(Request $request): JsonResponse
{
    $from = (int) $request->query->get('from', strtotime('-30 days'));
    $to   = (int) $request->query->get('to', time());

    // appointments_by_day: GROUP BY DATE(FROM_UNIXTIME(created_at))
    // revenue_by_day: از patient_sessions در بازه
    // subscription_sales_by_plan: از clinic_subscriptions در بازه
}

تغییر Frontend — DashboardPage.tsx

date range selector component:

type DateRangePreset = 'week' | 'month' | '3months' | 'custom';

interface DateRange {
  from: number; // Unix timestamp
  to: number;
}

function DateRangeSelector({ value, onChange }: {
  value: DateRange;
  onChange: (r: DateRange) => void;
}) {
  // preset buttons + PersianCalendar برای custom range
}

نمودارها با Recharts:

import { LineChart, Line, BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';

// chart نوبت‌ها
<ResponsiveContainer width="100%" height={250}>
  <LineChart data={chartsData?.appointments_by_day}>
    <XAxis dataKey="date" tickFormatter={d => formatDate(d)} />
    <YAxis />
    <Tooltip />
    <Line dataKey="count" stroke="#3b82f6" />
  </LineChart>
</ResponsiveContainer>

// chart درآمد
<BarChart data={chartsData?.revenue_by_day}>
  <Bar dataKey="amount_rials" fill="#10b981" />
</BarChart>

نصب dependency:

ddev exec yarn add recharts
ddev exec yarn add @types/recharts  # اگر نیاز بود