feat: complete redesign of the appointments page with new UI and functionality
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
# بازطراحی کامل صفحه نوبتها (AppointmentsPage)
|
||||
|
||||
## هدف
|
||||
صفحه `/admin/appointments` باید کاملاً بازطراحی شود تا شبیه به تصاویر مرجع باشد.
|
||||
دو حالت نمایش وجود دارد: **جدولی** و **زمانبندی**. هر دو حالت date-based هستند (نه pagination کلی).
|
||||
|
||||
---
|
||||
|
||||
## یک کامپوننت برای همه نقشها
|
||||
|
||||
**همه پنلها — دکتر، کلینیک، ادمین — دقیقاً همین صفحه را میبینند.** یک کامپوننت `AppointmentsPage.tsx` برای هر سه نقش. تفاوتها فقط در رفتار دادهها است، نه UI:
|
||||
|
||||
| ویژگی | ادمین | کلینیک | دکتر |
|
||||
|-------|-------|--------|------|
|
||||
| API لیست نوبتها | `/api/v1/admin/appointments` | `/api/v1/my/appointments` | `/api/v1/my/appointments` |
|
||||
| API slotهای خالی | `/api/v1/appointment-slots` | `/api/v1/appointment-slots` | `/api/v1/appointment-slots` |
|
||||
| dropdown پرسنل | همه دکترها | فقط دکترهای کلینیک | فقط خودش (auto-select) |
|
||||
| Doctor Tabs | نمایش داده نشود | ✅ نمایش (اگر ≥۲ دکتر) | نمایش داده نشود |
|
||||
| ثبت نوبت | با patient_mobile | با patient_mobile | با patient_mobile |
|
||||
| تغییر وضعیت | ✅ | ✅ | ✅ |
|
||||
|
||||
**نکته**: وقتی `primaryRole === 'doctor'`، دکتر UUID از `useAuthStore().dbUuid` گرفته میشود و dropdown پرسنل auto-select + read-only است.
|
||||
|
||||
**نکته**: وقتی `primaryRole === 'clinic'`، لیست دکترهای قابل انتخاب از نوبتهای برگشتی استخراج میشود (unique `doctor_uuid` + `doctor_name`).
|
||||
|
||||
---
|
||||
|
||||
## ساختار کلی صفحه
|
||||
|
||||
### ۱. نوار آمار بالا (Stats Bar)
|
||||
چهار کارت آمار **امروز** (نه کل):
|
||||
- **کل نوبتهای امروز** — icon: شبکه نقطهای بنفش
|
||||
- **نوبتهای انجام شده** — icon: آدم سبز
|
||||
- **مراجعین در انتظار** — icon: ساعت نارنجی
|
||||
- **نوبتهای لغو شده** — icon: ضربدر قرمز
|
||||
|
||||
هر کارت: عدد بزرگ + برچسب + آیکون گرافیکی رنگی.
|
||||
داده از API: `GET /api/v1/admin/appointments/today-stats?date=YYYY-MM-DD`
|
||||
پاسخ: `{ total, completed, waiting, cancelled }`
|
||||
|
||||
---
|
||||
|
||||
### ۲. نوار کنترل (Toolbar)
|
||||
|
||||
```
|
||||
[+ نوبت جدید] [آیکون جدول] [نمایش جدولی] [زمانبندی] [پرسنل را انتخاب کنید ▼] [←] [۱۴۰۳/۰۶/۰۵] [→] [📅]
|
||||
```
|
||||
|
||||
**اجزا:**
|
||||
- دکمه **"+ نوبت جدید"**: primary، باز میکند modal ثبت نوبت
|
||||
- **تاگل نما**: دو تب inline — "نمایش جدولی" (active=رنگی) و "زمانبندی"
|
||||
- **انتخاب پرسنل**: dropdown با لیست پزشکان — برای ادمین همه، برای کلینیک پزشکان خودش
|
||||
- **ناوبری تاریخ**: دکمههای `←` `→` برای روز قبلی/بعدی + تاریخ شمسی + آیکون تقویم که PersianCalendar popup باز میکند
|
||||
- **تقویم popup شمسی**: ماه/سال فارسی، روزهای هفته فارسی (ش ی د س چ پ ج)، امروز highlight خاکستری، روز انتخابی circle آبی، دکمههای ماه قبل/بعد
|
||||
|
||||
**نکته مهم**: نما date-based است — هر بار یک روز خاص نمایش داده میشود. پیشفرض = امروز.
|
||||
|
||||
---
|
||||
|
||||
### ۳. سیستم وضعیتها
|
||||
|
||||
**وضعیتهای واقعی backend** (entity `Appointment.php`):
|
||||
|
||||
| نام نمایشی | backend value (`STATUS_*`) | رنگ |
|
||||
|-----------------|----------------------------|------------|
|
||||
| رزرو شده | `pending` | آبی |
|
||||
| تأیید شده | `confirmed` | سبز |
|
||||
| تکمیل شده | `completed` | سبز تیره |
|
||||
| لغو پزشک | `cancelled_by_doctor` | قرمز |
|
||||
| لغو بیمار | `cancelled_by_user` | قرمز |
|
||||
| غیبت | `no_show` | خاکستری |
|
||||
| منقضی شده | `expired` | خاکستری |
|
||||
|
||||
**ماشین حالت (ALLOWED_TRANSITIONS)**:
|
||||
- `pending` → `confirmed` | `cancelled_by_doctor` | `cancelled_by_user` | `expired`
|
||||
- `confirmed` → `completed` | `cancelled_by_doctor` | `cancelled_by_user` | `no_show`
|
||||
|
||||
**PATCH status موجود** در `AppointmentController.php`:
|
||||
```
|
||||
PATCH /api/v1/appointment/{uuid}/status
|
||||
Body: { "status": "confirmed", "version": 1 }
|
||||
```
|
||||
دارای optimistic lock (version field). دکتر و ادمین هر دو مجاز هستند.
|
||||
|
||||
**نکته مهم**: وضعیتهایی مثل `waiting_for_payment`, `checked_in`, `waiting`, `in_progress`, `visited` که در frontend قدیمی بودند در entity وجود ندارند. فقط از وضعیتهای بالا استفاده شود.
|
||||
|
||||
**تغییر inline وضعیت**: کلیک روی badge → dropdown با دایرههای رنگی → انتخاب → PATCH:
|
||||
```
|
||||
PATCH /api/v1/admin/appointment/{uuid}/status
|
||||
Body: { "status": "visited" }
|
||||
```
|
||||
پس از موفقیت: فقط cache همان query را invalidate کند (بدون reload صفحه).
|
||||
|
||||
---
|
||||
|
||||
### ۴. نمای جدولی (Table View)
|
||||
|
||||
**ستونها**:
|
||||
`ردیف` | `نام بیمار` | `شماره تماس` | `شروع` | `پایان` | `وضعیت` | `عملیات`
|
||||
|
||||
- **ردیف**: شماره ردیف ساده
|
||||
- **شروع / پایان**: ساعت HH:MM
|
||||
- **وضعیت**: badge قابل کلیک با `▼` → dropdown تغییر وضعیت
|
||||
- **عملیات**: دکمه `...` → منو: مشاهده جزئیات، لغو نوبت
|
||||
|
||||
**API**: `GET /api/v1/admin/appointments?date=YYYY-MM-DD&doctor_uuid=...&limit=100`
|
||||
(در این نما limit بالا، بدون pagination — همه نوبتهای یک روز)
|
||||
|
||||
---
|
||||
|
||||
### ۵. نمای زمانبندی (Schedule View)
|
||||
|
||||
**بالا**: Doctor Tabs — تب برای هر پزشک، کلیک = سوئیچ به نوبتهای آن دکتر
|
||||
|
||||
**Layout** (RTL):
|
||||
```
|
||||
[ کارتهای نوبت — ستون عریض چپ ] [ ● ۰۸:۰۰ — محور زمان راست ]
|
||||
```
|
||||
|
||||
**محور زمان (Time Axis)**:
|
||||
- خط عمودی نقطهای (dashed) از بالا به پایین
|
||||
- نقطه ● در زمان شروع هر slot
|
||||
- label زمان فارسی کنار نقطه (۰۸:۰۰، ۰۸:۴۰)
|
||||
|
||||
**کارت نوبت پر**:
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ ▼ ویزیت شده ۰۸:۰۰ ● ─ ─ ─ ─ ─ ─ │ ← header
|
||||
│ ۰۸:۳۵ ● │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ 👤 ساغر صابری نژاد 📞 ۰۹۳۵۶۶۱۹۴۳۸ │ ← body
|
||||
│ سرویس: [نام سرویس] [+ اضافه] │
|
||||
├────────────────────────────────────────────────────────────┤
|
||||
│ [عملیات ...] │ ← footer
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
رنگبندی: border + background-tint متناسب با وضعیت:
|
||||
- ویزیت شده: border سبز، background سبز ۵٪
|
||||
- لغو شده: border قرمز، background قرمز ۵٪
|
||||
- در حال پیگیری: border نارنجی، background نارنجی ۵٪
|
||||
- سالن: border بنفش، background بنفش ۵٪
|
||||
- ثبت شده/قطعی: border آبی، background آبی ۵٪
|
||||
|
||||
**کارت slot خالی**:
|
||||
```
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
|
||||
│ ⊕ نوبت جدید │
|
||||
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
|
||||
```
|
||||
- border dashed آبی کمرنگ
|
||||
- کلیک → modal ثبت نوبت با doctor_uuid + slot_start/end پیشپر شده
|
||||
|
||||
**API برای نمای زمانبندی**:
|
||||
`GET /api/v1/appointment-slots?doctor_uuid=...&date=YYYY-MM-DD`
|
||||
باید slotهای پر را هم برگرداند با اطلاعات نوبت:
|
||||
```json
|
||||
{
|
||||
"slots": [
|
||||
{
|
||||
"start": 1234567890,
|
||||
"end": 1234568490,
|
||||
"label": "09:10",
|
||||
"is_available": false,
|
||||
"appointment": {
|
||||
"uuid": "...",
|
||||
"patient_name": "...",
|
||||
"patient_mobile": "...",
|
||||
"status": "visited",
|
||||
"service_name": "..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"start": 1234569000,
|
||||
"end": 1234569600,
|
||||
"label": "09:45",
|
||||
"is_available": true,
|
||||
"appointment": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## وضعیت Backend موجود (بررسی شده)
|
||||
|
||||
### ✅ موجود و قابل استفاده
|
||||
| Endpoint | وضعیت |
|
||||
|----------|-------|
|
||||
| `GET /api/v1/appointment-slots?doctor_uuid=...&date=YYYY-MM-DD` | ✅ موجود — **فقط slotهای خالی** برمیگرداند |
|
||||
| `POST /api/v1/appointment` | ✅ موجود — برای کاربر لاگینشده |
|
||||
| `POST /api/v1/admin/appointment` | ✅ موجود — برای ادمین با patient_mobile |
|
||||
| `PATCH /api/v1/appointment/{uuid}/status` | ✅ موجود — با optimistic lock و transition validation |
|
||||
| `GET /api/v1/admin/appointments?date=...` | باید بررسی شود آیا date filter دارد |
|
||||
|
||||
### 🔴 ندارد — باید اضافه شود
|
||||
|
||||
**۱. آمار امروز** — در `AdminApiController`:
|
||||
```php
|
||||
#[Route('/api/v1/admin/appointments/today-stats', methods: ['GET'])]
|
||||
// پارامتر: ?date=YYYY-MM-DD
|
||||
// منطق: COUNT GROUP BY status با DATE(FROM_UNIXTIME(slot_start)) = :date
|
||||
// پاسخ: { total, completed, waiting, cancelled }
|
||||
```
|
||||
|
||||
**۲. Slotهای کامل (پر + خالی)** — برای نمای زمانبندی:
|
||||
|
||||
**روش پیشنهادی (بدون backend جدید)**:
|
||||
- Frontend دو query موازی میزند:
|
||||
1. `GET /api/v1/appointment-slots?doctor_uuid=...&date=...` → لیست slotهای خالی
|
||||
2. `GET /api/v1/admin/appointments?date=...&doctor_uuid=...` → لیست نوبتهای پر
|
||||
- Merge در frontend: هر slot یا `{ is_available: true }` یا `{ is_available: false, appointment: {...} }`
|
||||
|
||||
اگر merge پیچیده شد، گزینه دوم اضافه کردن param به slot endpoint:
|
||||
```
|
||||
GET /api/v1/appointment-slots?doctor_uuid=...&date=...&include_booked=1
|
||||
```
|
||||
که slotهای رزروشده را هم با فیلد `appointment` برمیگرداند.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## ⭐ مهمترین Feature: ثبت نوبت از نمای زمانبندی
|
||||
|
||||
### پیششرط: دکتر باید برنامه هفتگی داشته باشد
|
||||
|
||||
**جریان بررسی**:
|
||||
1. وقتی دکتری انتخاب میشود، ابتدا `GET /api/v1/appointment-settings/weekly-schedule/{doctor_uuid}` فراخوانی شود
|
||||
2. اگر `404` برگشت → نوار هشدار نمایش داده شود:
|
||||
```
|
||||
⚠️ دکتر [نام] هنوز برنامه هفتگی تنظیم نکرده است.
|
||||
[تنظیم برنامه] ← لینک به صفحه تنظیمات دکتر
|
||||
```
|
||||
3. اگر schedule موجود بود → نوبتها بر اساس آن محاسبه شوند
|
||||
|
||||
**Slot Format خروجی `SlotCalculatorService`**:
|
||||
```json
|
||||
{
|
||||
"start": 1718438400,
|
||||
"end": 1718439600,
|
||||
"start_time": "09:00",
|
||||
"end_time": "09:20",
|
||||
"location_id": 1973
|
||||
}
|
||||
```
|
||||
فیلد `label` برای نمایش: `"09:00"` (از `start_time`)
|
||||
|
||||
### جریان ثبت نوبت از slot خالی (اصلیترین UX)
|
||||
|
||||
کلیک روی کارت `+ نوبت جدید` در نمای زمانبندی:
|
||||
|
||||
```
|
||||
┌──────────────────────────────┐
|
||||
│ ثبت نوبت — ۰۹:۱۰ تا ۰۹:۳۰ │
|
||||
│ دکتر: [نام دکتر] │
|
||||
│ ─────────────────────────── │
|
||||
│ موبایل بیمار: [___________] │ ← فقط این فیلد!
|
||||
│ [ثبت نوبت] [انصراف] │
|
||||
└──────────────────────────────┘
|
||||
```
|
||||
|
||||
- **تنها یک فیلد ورودی**: شماره موبایل بیمار
|
||||
- doctor_uuid + slot_start + slot_end از slot کلیکشده پیشپر هستند
|
||||
- Submit → `POST /api/v1/admin/appointment` با `{ doctor_uuid, slot_start, slot_end, patient_mobile }`
|
||||
- موفقیت → slot خالی تبدیل به کارت نوبت `pending` میشود (بدون reload کل صفحه)
|
||||
|
||||
**برای نقش دکتر/منشی** (نه ادمین):
|
||||
- بیمار را با موبایل پیدا کند
|
||||
- اگر کاربر یافت نشد → خطا: "بیمار با این شماره در سیستم یافت نشد"
|
||||
- (نمیتوان کاربر جدید از اینجا ساخت)
|
||||
|
||||
### Doctor Tabs در داشبورد کلینیک
|
||||
|
||||
وقتی `primaryRole === 'clinic'`:
|
||||
- تبهای دکتر بالای نمای زمانبندی نمایش داده شوند
|
||||
- هر تب: نام دکتر
|
||||
- کلیک روی تب → نمایش نوبتهای آن دکتر برای تاریخ انتخابی
|
||||
- دادهها از `GET /api/v1/admin/appointments?date=...` فیلتر شده با `doctor_uuid`
|
||||
- برای گرفتن لیست دکترهای کلینیک: از نوبتهای برگشتی unique doctor_name/uuid استخراج شود
|
||||
|
||||
---
|
||||
|
||||
## کامپوننتهای جدید Frontend
|
||||
|
||||
### `PersianCalendar.tsx`
|
||||
```tsx
|
||||
interface Props {
|
||||
value: string; // YYYY-MM-DD
|
||||
onChange: (v: string) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
```
|
||||
- محاسبه ماه/سال شمسی از `Intl.DateTimeFormat('fa-IR-u-ca-persian')`
|
||||
- گرید ۷ ستونه با padding برای روز اول ماه
|
||||
- تبدیل روز انتخابی شمسی → Gregorian: از `new Date()` با تاریخ ISO ساختهشده
|
||||
|
||||
### `AppointmentStatusDropdown.tsx`
|
||||
```tsx
|
||||
interface Props {
|
||||
uuid: string;
|
||||
currentStatus: string;
|
||||
onChanged: () => void;
|
||||
}
|
||||
```
|
||||
- دکمه badge با `▼`
|
||||
- dropdown با لیست وضعیتها و دایره رنگی
|
||||
- useMutation برای PATCH
|
||||
- بعد از موفقیت: invalidate query
|
||||
|
||||
---
|
||||
|
||||
## فایلهای تأثیرپذیر
|
||||
|
||||
| فایل | تغییر |
|
||||
|------|-------|
|
||||
| `assets/admin/pages/AppointmentsPage.tsx` | بازنویسی کامل |
|
||||
| `assets/admin/components/ui/PersianCalendar.tsx` | جدید |
|
||||
| `assets/admin/components/ui/PersianDateInput.tsx` | افزودن PersianCalendar popup |
|
||||
| `assets/admin/components/ui/AppointmentStatusDropdown.tsx` | جدید |
|
||||
| `assets/admin/styles.css` | CSS schedule view + status colors |
|
||||
| `src/Admin/Controller/AdminApiController.php` | today-stats + PATCH status |
|
||||
| `src/Appointment/Controller/AppointmentController.php` | بهبود slots |
|
||||
| `docs/api/admin.md` | مستندسازی endpointهای جدید |
|
||||
| `docs/api/appointment.md` | مستندسازی بهبود slots |
|
||||
|
||||
---
|
||||
|
||||
## منطق محاسبه Slotها (SlotCalculatorService)
|
||||
|
||||
اولویتبندی:
|
||||
1. **Holiday** (تعطیلات) → هیچ slotای نیست
|
||||
2. **Date Override** با `active: false` → هیچ slotای نیست
|
||||
3. **Date Override** با `active: true` → از `custom_slots` آن روز استفاده شود
|
||||
4. **Weekly Schedule** → از sessionهای روز هفته مربوطه (ایندکس: شنبه=0 ... جمعه=6)
|
||||
|
||||
خروجی slot بعد از محاسبه و حذف slotهای رزروشده:
|
||||
```json
|
||||
{ "start": 1718438400, "end": 1718439600, "start_time": "09:00", "end_time": "09:20", "location_id": 1973 }
|
||||
```
|
||||
|
||||
این endpoint **فقط slotهای خالی** برمیگرداند (booked slots حذف شدهاند).
|
||||
|
||||
---
|
||||
|
||||
## نکات پیادهسازی
|
||||
|
||||
1. **Date-based**: queryKey شامل `selectedDate` — پیشفرض امروز (Gregorian)
|
||||
2. **Doctor state**: یک state مشترک `selectedDoctorUuid` برای هر دو نما
|
||||
3. **Schedule view — دو query موازی**:
|
||||
- `useQuery(['slots', doctorUuid, date])` → slotهای خالی از `/api/v1/appointment-slots`
|
||||
- `useQuery(['appointments', date, doctorUuid])` → نوبتهای پر از `/api/v1/admin/appointments`
|
||||
- Merge در frontend: آرایه کامل با `is_available` flag
|
||||
4. **Slot کلیک**: `onSlotClick(slot)` → `setBookingSlot(slot)` → mini modal با فقط یک فیلد موبایل
|
||||
5. **Optimistic lock**: PATCH status باید `version` را از نوبت بگیرد
|
||||
6. **Status transitions**: فقط انتقالهای مجاز از وضعیت فعلی در dropdown نشان داده شود
|
||||
7. **بررسی schedule**: اگر دکتر schedule نداشت هشدار نشان بده + لینک تنظیمات دکتر
|
||||
8. **محور زمان RTL**: CSS grid دو ستونه — کارتها چپ، محور زمان راست
|
||||
9. **Reload نکن**: بعد از هر عملیات فقط `queryClient.invalidateQueries`
|
||||
10. **وضعیتهای درست**: `pending`, `confirmed`, `completed`, `cancelled_by_doctor`, `cancelled_by_user`, `no_show`, `expired`
|
||||
|
||||
---
|
||||
|
||||
## ⭐ الزام دیزاین: دقیقاً شبیه تصاویر مرجع
|
||||
|
||||
> **این صفحه باید pixel-perfect شبیه تصاویر مرجع باشد. هیچ اجزایی از دیزاین نباید تغییر کند.**
|
||||
|
||||
---
|
||||
|
||||
### همه تاریخها شمسی (Jalali)
|
||||
|
||||
- **تمام** تاریخهای نمایشی — فیلتر، جدول، کارتها، محور زمان، تقویم popup — باید شمسی باشند
|
||||
- از `Intl.DateTimeFormat('fa-IR-u-ca-persian')` برای تبدیل استفاده شود
|
||||
- input فیلتر تاریخ: مقدار داخلی `YYYY-MM-DD` میلادی باشد (برای API) ولی **نمایش** شمسی
|
||||
- تقویم popup باید ماه/سال/روز شمسی نشان دهد
|
||||
- هیچ تاریخی به فرمت `mm/dd/yyyy` یا میلادی به کاربر نمایش داده نشود
|
||||
|
||||
---
|
||||
|
||||
### مشخصات دقیق دیزاین از تصاویر مرجع
|
||||
|
||||
#### Stats Bar
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────────────┐
|
||||
│ کل نوبتهای امروز │ نوبتهای انجام شده │ مراجعین در انتظار │ نوبتهای لغو شده │
|
||||
│ [آیکون بنفش] │ [آیکون سبز] │ [آیکون نارنجی] │ [آیکون قرمز] │
|
||||
│ ۲۳۶ │ ۲۰۰ │ ۲۳۶ │ ۱۲ │
|
||||
└───────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
- یک کارت سفید با border کمرنگ — ۴ بخش با divider عمودی بینشان
|
||||
- آیکونها: دایره رنگی با SVG گرافیکی داخل (نه heroicon ساده)
|
||||
- بنفش: grid/شبکه نقطهای
|
||||
- سبز: فیگور آدم
|
||||
- نارنجی: ساعت شنی (hourglass)
|
||||
- قرمز: دایره با X
|
||||
- عدد bold بزرگ + متن label زیرش (ترتیب: label بالا، عدد پایین — از راست به چپ)
|
||||
|
||||
#### Toolbar
|
||||
```
|
||||
[+ نوبت جدید] [≡] | [نمایش جدولی] [زمانبندی] | [پرسنل را انتخاب کنید... ▼] | [<] [۱۴۰۳/۰۶/۰۵] [>] [📅]
|
||||
```
|
||||
- دکمه "نوبت جدید": آبی تیره، آیکون +، گرد
|
||||
- دکمه کنار آن: خاکستری border، آیکون ≡ (list/filter icon)
|
||||
- تبهای نما: "نمایش جدولی" (active=پسزمینه سفید، border) | "زمانبندی" (غیرactive=متن خاکستری)، کنار هم در یک pill container خاکستری کمرنگ
|
||||
- Dropdown پرسنل: کشیده، placeholder "پرسنل را انتخاب کنید..."، فاصله زیاد بین تبها و date nav
|
||||
- Date nav: دو فلش `<` `>`، تاریخ شمسی وسط، آیکون تقویم در راستترین موقعیت
|
||||
|
||||
#### جدول — ستونهای هدر دکتر
|
||||
```
|
||||
┌─────────────────────┬──────────────────────┐
|
||||
│ دکتر فتحی │ دکتر امینی فر │ ← سرتیتر گروهبندی دکتر
|
||||
├──────┬──────┬───────┼───────┬──────┬────────┤
|
||||
│ شروع │ پایان│ سرویس │ شروع │ پایان│ سرویس │ ← سرتیتر ستونها
|
||||
```
|
||||
- وقتی چند دکتر: ستونهای هر دکتر کنار هم، با سرتیتر دکتر spanning
|
||||
|
||||
#### Status Badge (inline قابل کلیک)
|
||||
- شکل: pill (border-radius کامل)
|
||||
- محتوا: `▼ [متن وضعیت]`
|
||||
- رنگبندی pill متناسب با وضعیت (همان رنگهای تعریفشده)
|
||||
|
||||
#### Status Dropdown (کلیک روی badge)
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ ○ ثبت شده │ ← دایره آبی توخالی + متن آبی
|
||||
│ ○ قطعی شده │ ← دایره سبز توخالی + متن سبز
|
||||
│ ○ در حال پیگیری │ ← دایره نارنجی توخالی + متن نارنجی
|
||||
│ ○ سالن │ ← دایره بنفش توخالی + متن بنفش
|
||||
│ ● ویزیت شده │ ← دایره سبز پر (وضعیت فعلی) + متن سبز
|
||||
│ ○ لغو شده │ ← دایره قرمز توخالی + متن قرمز
|
||||
└──────────────────────┘
|
||||
```
|
||||
- کارت سفید با shadow
|
||||
- هر گزینه: دایره رنگی (filled=وضعیت فعلی، outlined=بقیه) + متن رنگی
|
||||
- با کلیک روی گزینه: PATCH و بسته شدن dropdown
|
||||
|
||||
#### دکمه عملیات
|
||||
- متن "عملیات" + "..." در یک pill خاکستری کمرنگ
|
||||
- یا فقط "..." به عنوان icon button
|
||||
|
||||
#### تقویم Popup (کلیک روی آیکون 📅)
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ < تیر ۱۴۰۴ > │
|
||||
│ شنبه یکشنبه دوشنبه ... جمعه │
|
||||
│ ۱ ۲ ۳ ۴ ۵ ۶ ۷ │
|
||||
│ ۸ ۹ ۱۰ ۱۱ [۱۲] ۱۳ ۱۴ │ ← ۱۲ = روز انتخابی (circle آبی)
|
||||
│ ... │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
- ظاهر: کارت سفید، border کمرنگ، shadow
|
||||
- header: نام ماه شمسی + سال + دکمههای ماه قبل/بعد
|
||||
- روز هفته: ش | ی | د | س | چ | پ | ج
|
||||
- روز انتخابی: circle آبی solid
|
||||
- امروز: circle خاکستری کمرنگ (اگر با انتخابی فرق داشت)
|
||||
- Popup مانند calendar بسته میشود وقتی خارج از آن کلیک شود
|
||||
|
||||
#### Pagination
|
||||
```
|
||||
< 1 2 3 4 5 ... 20 >
|
||||
```
|
||||
- عدد فعال: آبی bold
|
||||
- دکمههای قبل/بعد: فلش `<` `>`
|
||||
Reference in New Issue
Block a user