Implement SMS panel user flow and patient records system; add wallet charging, automatic reminders, and patient session management with detailed database schema and user flows.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# معماری — تسک ۱۶: داشبورد هوشمند
|
||||
|
||||
## فایلهایی که تغییر میکنند
|
||||
|
||||
```
|
||||
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
|
||||
|
||||
```php
|
||||
#[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 با بازه زمانی
|
||||
|
||||
```php
|
||||
#[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:
|
||||
|
||||
```tsx
|
||||
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:
|
||||
|
||||
```tsx
|
||||
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:
|
||||
|
||||
```bash
|
||||
ddev exec yarn add recharts
|
||||
ddev exec yarn add @types/recharts # اگر نیاز بود
|
||||
```
|
||||
Reference in New Issue
Block a user