diff --git a/api/app/application/patients_repository.py b/api/app/application/patients_repository.py index a1ae985..2962867 100644 --- a/api/app/application/patients_repository.py +++ b/api/app/application/patients_repository.py @@ -1,6 +1,6 @@ -from typing import Sequence, Optional +from typing import Sequence, Optional, Tuple -from sqlalchemy import select +from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from app.domain.models import Patient @@ -10,10 +10,16 @@ class PatientsRepository: def __init__(self, db: AsyncSession): self.db = db - async def get_all(self) -> Sequence[Patient]: - stmt = select(Patient) + async def get_all(self, skip: int = 0, limit: int = 10) -> Tuple[Sequence[Patient], int]: + stmt = select(Patient).offset(skip).limit(limit) result = await self.db.execute(stmt) - return result.scalars().all() + patients = result.scalars().all() + + count_stmt = select(func.count()).select_from(Patient) + count_result = await self.db.execute(count_stmt) + total_count = count_result.scalar() + + return patients, total_count async def get_by_id(self, patient_id: int) -> Optional[Patient]: stmt = select(Patient).filter_by(id=patient_id) diff --git a/api/app/controllers/patients_router.py b/api/app/controllers/patients_router.py index fbcfa7e..5ff7b86 100644 --- a/api/app/controllers/patients_router.py +++ b/api/app/controllers/patients_router.py @@ -1,8 +1,9 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from app.database.session import get_db from app.domain.entities.patient import PatientEntity +from app.domain.entities.responses.paginated_patient import PaginatedPatientsResponseEntity from app.infrastructure.dependencies import get_current_user from app.infrastructure.patients_service import PatientsService @@ -11,16 +12,19 @@ router = APIRouter() @router.get( "/", - response_model=list[PatientEntity], - summary="Get all patients", - description="Returns a list of all patients", + response_model=PaginatedPatientsResponseEntity, + summary="Get all patients with pagination", + description="Returns a paginated list of patients and total count", ) async def get_all_patients( + page: int = Query(1, ge=1, description="Page number"), + page_size: int = Query(10, ge=1, le=100, description="Number of patients per page"), db: AsyncSession = Depends(get_db), user=Depends(get_current_user), ): patients_service = PatientsService(db) - return await patients_service.get_all_patients() + patients, total_count = await patients_service.get_all_patients(page, page_size) + return {"patients": patients, "total_count": total_count} @router.post( diff --git a/api/app/domain/entities/responses/paginated_patient.py b/api/app/domain/entities/responses/paginated_patient.py new file mode 100644 index 0000000..4b9ef15 --- /dev/null +++ b/api/app/domain/entities/responses/paginated_patient.py @@ -0,0 +1,8 @@ +from pydantic import BaseModel + +from app.domain.entities.patient import PatientEntity + + +class PaginatedPatientsResponseEntity(BaseModel): + patients: list[PatientEntity] + total_count: int diff --git a/api/app/infrastructure/patients_service.py b/api/app/infrastructure/patients_service.py index bb56f29..cb66830 100644 --- a/api/app/infrastructure/patients_service.py +++ b/api/app/infrastructure/patients_service.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Tuple from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession @@ -13,12 +13,13 @@ class PatientsService: def __init__(self, db: AsyncSession): self.patient_repository = PatientsRepository(db) - async def get_all_patients(self) -> list[PatientEntity]: - patients = await self.patient_repository.get_all() - return [ - self.model_to_entity(patient) - for patient in patients - ] + async def get_all_patients(self, page: int = 1, page_size: int = 10) -> Tuple[list[PatientEntity], int]: + skip = (page - 1) * page_size + patients, total_count = await self.patient_repository.get_all(skip=skip, limit=page_size) + return ( + [self.model_to_entity(patient) for patient in patients], + total_count + ) async def create_patient(self, patient: PatientEntity) -> PatientEntity: patient_model = self.entity_to_model(patient) diff --git a/web-app/src/Api/patientsApi.js b/web-app/src/Api/patientsApi.js index 2350417..a740d97 100644 --- a/web-app/src/Api/patientsApi.js +++ b/web-app/src/Api/patientsApi.js @@ -7,9 +7,11 @@ export const patientsApi = createApi({ tagTypes: ['Patient'], endpoints: (builder) => ({ getPatients: builder.query({ - query: () => '/patients/', - providesTags: ['Patient'], - refetchOnMountOrArgChange: 5 + query: ({ page, pageSize }) => ({ + url: '/patients/', + params: { page, page_size: pageSize }, + }), + providesTags: ['Patients'], }), addPatient: builder.mutation({ query: (patient) => ({ diff --git a/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx b/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx index 153de88..0f818b0 100644 --- a/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx +++ b/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx @@ -25,39 +25,36 @@ import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.js import usePatients from "./usePatients.js"; import usePatientsUI from "./usePatientsUI.js"; -const {Option} = Select; -const {Title} = Typography; +const { Option } = Select; +const { Title } = Typography; const PatientsPage = () => { const patientsData = usePatients(); - const patientsUI = usePatientsUI(patientsData.patients); + const patientsUI = usePatientsUI(patientsData.patients, patientsData.totalCount); const columns = [ { title: "Фамилия", dataIndex: "last_name", key: "last_name", - sorter: (a, b) => a.last_name.localeCompare(b.last_name), - sortDirections: ["ascend", "descend"], + sorter: true, // Сортировка будет на сервере, если добавить }, { title: "Имя", dataIndex: "first_name", key: "first_name", - sorter: (a, b) => a.first_name.localeCompare(b.first_name), - sortDirections: ["ascend", "descend"], + sorter: true, }, { title: "Отчество", dataIndex: "patronymic", key: "patronymic", - sortDirections: ["ascend", "descend"], + sorter: true, }, { title: "Дата рождения", dataIndex: "birthday", - sorter: (a, b) => new Date(a.birthday).getTime() - new Date(b.birthday).getTime(), - sortDirections: ["ascend", "descend"], + sorter: true, render: patientsUI.formatDate, }, { @@ -76,7 +73,6 @@ const PatientsPage = () => {