From a2635ed03eba9e462b164910b1a59314a7529209 Mon Sep 17 00:00:00 2001 From: andrei Date: Sat, 7 Jun 2025 14:54:05 +0500 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BF=D0=B0=D1=86=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=B9=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/application/patients_repository.py | 31 +++++++++++++++++-- api/app/controllers/patients_router.py | 3 +- api/app/infrastructure/patients_service.py | 5 +-- web-app/src/Api/patientsApi.js | 4 +-- .../Pages/PatientsPage/PatientsPage.jsx | 4 +-- .../Pages/PatientsPage/usePatients.js | 6 ++-- .../Pages/PatientsPage/usePatientsUI.js | 8 +++-- 7 files changed, 44 insertions(+), 17 deletions(-) diff --git a/api/app/application/patients_repository.py b/api/app/application/patients_repository.py index 2962867..b9f5b52 100644 --- a/api/app/application/patients_repository.py +++ b/api/app/application/patients_repository.py @@ -1,6 +1,6 @@ from typing import Sequence, Optional, Tuple -from sqlalchemy import select, func +from sqlalchemy import select, func, or_ from sqlalchemy.ext.asyncio import AsyncSession from app.domain.models import Patient @@ -10,12 +10,37 @@ class PatientsRepository: def __init__(self, db: AsyncSession): self.db = db - async def get_all(self, skip: int = 0, limit: int = 10) -> Tuple[Sequence[Patient], int]: - stmt = select(Patient).offset(skip).limit(limit) + async def get_all(self, skip: int = 0, limit: int = 10, search: str = None) -> Tuple[Sequence[Patient], int]: + stmt = select(Patient) + + if search: + search = f"%{search}%" + stmt = stmt.filter( + or_( + Patient.last_name.ilike(search), + Patient.first_name.ilike(search), + Patient.patronymic.ilike(search), + Patient.email.ilike(search), + Patient.phone.ilike(search) + ) + ) + + stmt = stmt.offset(skip).limit(limit) result = await self.db.execute(stmt) patients = result.scalars().all() count_stmt = select(func.count()).select_from(Patient) + if search: + search = f"%{search}%" + count_stmt = count_stmt.filter( + or_( + Patient.last_name.ilike(search), + Patient.first_name.ilike(search), + Patient.patronymic.ilike(search), + Patient.email.ilike(search), + Patient.phone.ilike(search) + ) + ) count_result = await self.db.execute(count_stmt) total_count = count_result.scalar() diff --git a/api/app/controllers/patients_router.py b/api/app/controllers/patients_router.py index 5ff7b86..ebf33e3 100644 --- a/api/app/controllers/patients_router.py +++ b/api/app/controllers/patients_router.py @@ -19,11 +19,12 @@ router = APIRouter() 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"), + search: str = Query(None, description="Search term for filtering patients"), db: AsyncSession = Depends(get_db), user=Depends(get_current_user), ): patients_service = PatientsService(db) - patients, total_count = await patients_service.get_all_patients(page, page_size) + patients, total_count = await patients_service.get_all_patients(page, page_size, search) return {"patients": patients, "total_count": total_count} diff --git a/api/app/infrastructure/patients_service.py b/api/app/infrastructure/patients_service.py index cb66830..6b2e033 100644 --- a/api/app/infrastructure/patients_service.py +++ b/api/app/infrastructure/patients_service.py @@ -13,9 +13,10 @@ class PatientsService: def __init__(self, db: AsyncSession): self.patient_repository = PatientsRepository(db) - async def get_all_patients(self, page: int = 1, page_size: int = 10) -> Tuple[list[PatientEntity], int]: + async def get_all_patients(self, page: int = 1, page_size: int = 10, search: str = None) -> Tuple[ + list[PatientEntity], int]: skip = (page - 1) * page_size - patients, total_count = await self.patient_repository.get_all(skip=skip, limit=page_size) + patients, total_count = await self.patient_repository.get_all(skip=skip, limit=page_size, search=search) return ( [self.model_to_entity(patient) for patient in patients], total_count diff --git a/web-app/src/Api/patientsApi.js b/web-app/src/Api/patientsApi.js index a740d97..4a3b082 100644 --- a/web-app/src/Api/patientsApi.js +++ b/web-app/src/Api/patientsApi.js @@ -7,9 +7,9 @@ export const patientsApi = createApi({ tagTypes: ['Patient'], endpoints: (builder) => ({ getPatients: builder.query({ - query: ({ page, pageSize }) => ({ + query: ({ page, pageSize, search }) => ({ url: '/patients/', - params: { page, page_size: pageSize }, + params: { page, page_size: pageSize, search: search || undefined }, }), providesTags: ['Patients'], }), diff --git a/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx b/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx index 0f818b0..96bbc5f 100644 --- a/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx +++ b/web-app/src/Components/Pages/PatientsPage/PatientsPage.jsx @@ -37,7 +37,7 @@ const PatientsPage = () => { title: "Фамилия", dataIndex: "last_name", key: "last_name", - sorter: true, // Сортировка будет на сервере, если добавить + sorter: true, }, { title: "Имя", @@ -109,8 +109,6 @@ const PatientsPage = () => { /> ); - console.log(patientsData.isLoading) - return (
<TeamOutlined/> Пациенты diff --git a/web-app/src/Components/Pages/PatientsPage/usePatients.js b/web-app/src/Components/Pages/PatientsPage/usePatients.js index c5419e3..abe4f1d 100644 --- a/web-app/src/Components/Pages/PatientsPage/usePatients.js +++ b/web-app/src/Components/Pages/PatientsPage/usePatients.js @@ -6,17 +6,15 @@ import { import { useSelector } from "react-redux"; const usePatients = () => { - const { currentPage, pageSize } = useSelector(state => state.patientsUI); + const { currentPage, pageSize, searchText } = useSelector(state => state.patientsUI); const { data = { patients: [], total_count: 0 }, isLoading, isError } = useGetPatientsQuery( - { page: currentPage, pageSize }, + { page: currentPage, pageSize, search: searchText }, { pollingInterval: 20000, } ); - console.log(data); - const [deletePatient] = useDeletePatientMutation(); const handleDeletePatient = async (patientId) => { diff --git a/web-app/src/Components/Pages/PatientsPage/usePatientsUI.js b/web-app/src/Components/Pages/PatientsPage/usePatientsUI.js index e5ce8cb..7cf62bc 100644 --- a/web-app/src/Components/Pages/PatientsPage/usePatientsUI.js +++ b/web-app/src/Components/Pages/PatientsPage/usePatientsUI.js @@ -1,5 +1,6 @@ -import { useEffect, useMemo } from "react"; +import { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; +import { debounce } from "lodash"; import { closeModal, openModal, @@ -34,7 +35,10 @@ const usePatientsUI = (patients, totalCount) => { const formItemStyle = { width: "100%" }; const viewModIconStyle = { marginRight: 8 }; - const handleSetSearchText = (value) => dispatch(setSearchText(value)); + const handleSetSearchText = debounce((value) => { + dispatch(setSearchText(value)); + dispatch(setCurrentPage(1)); // Сбрасываем на первую страницу при новом поиске + }, 300); const handleSetSortOrder = (value) => dispatch(setSortOrder(value)); const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page)); const handleSetPageSize = (size) => dispatch(setPageSize(size));