feat: implement filtered and paginated appointment retrieval for doctors
This commit is contained in:
@@ -642,10 +642,44 @@ class AppointmentController extends BaseController
|
||||
return $this->error(ErrorCodes::ERR_ACCESS_DENIED, 'دسترسی ممنوع', 403);
|
||||
}
|
||||
|
||||
$status = $request->query->get('status');
|
||||
$appointments = $this->appointmentRepo->findByDoctor($doctor, $status, $scopeClinic);
|
||||
// بدون هیچ پارامتر فیلتر/صفحهبندی، رفتار قدیمی (لیست کامل، پاسخ تودرتو) حفظ
|
||||
// میشود تا کلاینتهای موجود نشکنند. با هر فیلتری پاسخ صفحهبندیشده میآید.
|
||||
$filterKeys = ['statuses', 'from', 'to', 'q', 'service_uuid', 'page', 'limit'];
|
||||
$isFiltered = (bool) array_filter($filterKeys, fn(string $k) => $request->query->has($k));
|
||||
|
||||
return $this->success(['data' => array_map(fn(Appointment $a) => $a->toArray(), $appointments)]);
|
||||
if (!$isFiltered) {
|
||||
$status = $request->query->get('status');
|
||||
$appointments = $this->appointmentRepo->findByDoctor($doctor, $status, $scopeClinic);
|
||||
|
||||
return $this->success(['data' => array_map(fn(Appointment $a) => $a->toArray(), $appointments)]);
|
||||
}
|
||||
|
||||
$statuses = $request->query->all('statuses');
|
||||
if ($statuses === [] && $request->query->get('status')) {
|
||||
$statuses = [$request->query->get('status')];
|
||||
}
|
||||
|
||||
$page = max(1, (int) $request->query->get('page', 1));
|
||||
$limit = min(100, max(1, (int) $request->query->get('limit', 20)));
|
||||
|
||||
$result = $this->appointmentRepo->searchByDoctor(
|
||||
doctor: $doctor,
|
||||
statuses: array_values(array_filter($statuses, fn($s) => is_string($s) && $s !== '')),
|
||||
clinic: $scopeClinic,
|
||||
from: $request->query->has('from') ? (int) $request->query->get('from') : null,
|
||||
to: $request->query->has('to') ? (int) $request->query->get('to') : null,
|
||||
query: $request->query->get('q'),
|
||||
serviceUuid: $request->query->get('service_uuid'),
|
||||
page: $page,
|
||||
limit: $limit,
|
||||
);
|
||||
|
||||
return $this->paginated(
|
||||
array_map(fn(Appointment $a) => $a->toArray(), $result['items']),
|
||||
$result['total'],
|
||||
$page,
|
||||
$limit,
|
||||
);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
|
||||
@@ -182,6 +182,65 @@ class AppointmentRepository extends ServiceEntityRepository
|
||||
return $this->findBy($criteria, ['slotStart' => 'ASC']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtered + paginated appointment list for one doctor — backs the doctor
|
||||
* dashboard filter bar. Kept separate from findByDoctor() so existing
|
||||
* unfiltered callers keep their plain-array contract.
|
||||
*
|
||||
* @param string[] $statuses empty = no status restriction
|
||||
* @return array{items: Appointment[], total: int}
|
||||
*/
|
||||
public function searchByDoctor(
|
||||
Doctor $doctor,
|
||||
array $statuses = [],
|
||||
?Clinic $clinic = null,
|
||||
?int $from = null,
|
||||
?int $to = null,
|
||||
?string $query = null,
|
||||
?string $serviceUuid = null,
|
||||
int $page = 1,
|
||||
int $limit = 20,
|
||||
): array {
|
||||
$qb = $this->createQueryBuilder('a')
|
||||
->join('a.user', 'u')
|
||||
->where('a.doctor = :doctor')
|
||||
->setParameter('doctor', $doctor);
|
||||
|
||||
if ($statuses !== []) {
|
||||
$qb->andWhere('a.status IN (:statuses)')->setParameter('statuses', $statuses);
|
||||
}
|
||||
// همان محدودسازی محیط که findByDoctor دارد: نوبت مطب شخصی به کلینیک نشت نکند.
|
||||
if ($clinic !== null) {
|
||||
$qb->andWhere('a.clinic = :clinic')->setParameter('clinic', $clinic);
|
||||
}
|
||||
if ($from !== null) {
|
||||
$qb->andWhere('a.slotStart >= :from')->setParameter('from', $from);
|
||||
}
|
||||
if ($to !== null) {
|
||||
$qb->andWhere('a.slotStart <= :to')->setParameter('to', $to);
|
||||
}
|
||||
if ($serviceUuid !== null && $serviceUuid !== '') {
|
||||
$qb->join('a.serviceItem', 'si')
|
||||
->andWhere('si.uuid = :serviceUuid')
|
||||
->setParameter('serviceUuid', $serviceUuid);
|
||||
}
|
||||
// نام/موبایل هم روی فیلدهای خودِ نوبت ذخیره میشود و هم روی کاربر؛ هر دو جستوجو میشوند.
|
||||
if ($query !== null && trim($query) !== '') {
|
||||
$qb->andWhere('a.patientName LIKE :q OR a.patientMobile LIKE :q OR u.realName LIKE :q OR u.mobileNumber LIKE :q')
|
||||
->setParameter('q', '%' . trim($query) . '%');
|
||||
}
|
||||
|
||||
$total = (int) (clone $qb)->select('COUNT(a.id)')->getQuery()->getSingleScalarResult();
|
||||
|
||||
$items = $qb->orderBy('a.slotStart', 'ASC')
|
||||
->setFirstResult(max(0, ($page - 1) * $limit))
|
||||
->setMaxResults($limit)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
return ['items' => $items, 'total' => $total];
|
||||
}
|
||||
|
||||
/**
|
||||
* نوبتهای یک بیمار در یک کلینیک — بر پایهٔ خودِ محیطِ ثبتشدهٔ نوبت، تا غیرفعال
|
||||
* شدنِ بعدیِ پزشک تاریخچه را از پروندهٔ کلینیک حذف نکند.
|
||||
|
||||
Reference in New Issue
Block a user