From 1541aba89f716dfd33b7ec7b18a2322231423562 Mon Sep 17 00:00:00 2001 From: andrei Date: Fri, 4 Jul 2025 07:06:57 +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=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=20=D0=B8?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D1=80=D0=B8=D0=B8=20=D0=BB=D0=B8=D0=BD=D0=B7?= =?UTF-8?q?=20=D0=BF=D0=BE=20=D0=BF=D0=B0=D1=86=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлен API endpoint и query для получения истории линз по ID пациента. --- api/app/Dockerfile | 13 +++++++- api/app/application/lens_issues_repository.py | 23 +++++++++---- api/app/controllers/lens_issues_router.py | 32 ++++++++++++++----- api/app/infrastructure/lens_issues_service.py | 32 +++++++++++++++---- web-app/src/Api/lensIssuesApi.js | 17 ++++++---- .../PatientFormModal/usePatientFormModal.js | 6 ++-- .../PatientViewModal/usePatientsViewModal.js | 21 ++++++++++++ 7 files changed, 112 insertions(+), 32 deletions(-) create mode 100644 web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/usePatientsViewModal.js diff --git a/api/app/Dockerfile b/api/app/Dockerfile index c0997f4..f845f49 100644 --- a/api/app/Dockerfile +++ b/api/app/Dockerfile @@ -1,11 +1,22 @@ FROM python:3.10-slim +RUN apt-get update && apt-get install -y \ + lsb-release \ + wget \ + gnupg \ + && rm -rf /var/lib/apt/lists/* + +RUN echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list \ + && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - + RUN apt-get update && apt-get install -y \ libpq-dev \ libmagic1 \ - postgresql-client \ + postgresql-client-17 \ && rm -rf /var/lib/apt/lists/* +RUN mkdir -p /app/backups && chmod 777 /app/backups + WORKDIR /app COPY req.txt . diff --git a/api/app/application/lens_issues_repository.py b/api/app/application/lens_issues_repository.py index 6d35336..97f3f94 100644 --- a/api/app/application/lens_issues_repository.py +++ b/api/app/application/lens_issues_repository.py @@ -13,13 +13,13 @@ class LensIssuesRepository: self.db = db async def get_all( - self, - skip: int = 0, - limit: int = 10, - search: Optional[str] = None, - sort_order: Literal["asc", "desc"] = "desc", - start_date: Optional[date] = None, - end_date: Optional[date] = None + self, + skip: int = 0, + limit: int = 10, + search: Optional[str] = None, + sort_order: Literal["asc", "desc"] = "desc", + start_date: Optional[date] = None, + end_date: Optional[date] = None ) -> Tuple[Sequence[LensIssue], int]: stmt = ( select(LensIssue) @@ -76,6 +76,15 @@ class LensIssuesRepository: return issues, total_count + async def get_by_patient_id(self, patient_id: int) -> Sequence[LensIssue]: + stmt = ( + select(LensIssue) + .filter_by(patient_id=patient_id) + .options(joinedload(LensIssue.lens)) + ) + result = await self.db.execute(stmt) + return result.scalars().all() + async def get_by_id(self, lens_issue_id: int) -> Optional[LensIssue]: stmt = select(LensIssue).filter_by(id=lens_issue_id) result = await self.db.execute(stmt) diff --git a/api/app/controllers/lens_issues_router.py b/api/app/controllers/lens_issues_router.py index 64f1e09..f2ab7f4 100644 --- a/api/app/controllers/lens_issues_router.py +++ b/api/app/controllers/lens_issues_router.py @@ -20,14 +20,14 @@ router = APIRouter() description="Returns a paginated list of lens issues with optional filtering and sorting", ) async def get_all_lens_issues( - page: int = Query(1, ge=1), - page_size: int = Query(10, ge=1, le=100), - search: Optional[str] = Query(None), - sort_order: Literal["asc", "desc"] = Query("desc"), - start_date: Optional[date] = Query(None), - end_date: Optional[date] = Query(None), - db: AsyncSession = Depends(get_db), - user=Depends(get_current_user), + page: int = Query(1, ge=1), + page_size: int = Query(10, ge=1, le=100), + search: Optional[str] = Query(None), + sort_order: Literal["asc", "desc"] = Query("desc"), + start_date: Optional[date] = Query(None), + end_date: Optional[date] = Query(None), + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), ): lens_issues_service = LensIssuesService(db) skip = (page - 1) * page_size @@ -44,6 +44,22 @@ async def get_all_lens_issues( total_count=total_count ) + +@router.get( + '/by-patient/{patient_id}/', + response_model=list[LensIssueEntity], + summary="Get lens issues by patients id", + description="Returns a paginated list of lens issues by patients id", +) +async def get_lens_issues_by_patient( + patient_id: int, + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), +): + lens_issues_service = LensIssuesService(db) + return await lens_issues_service.get_lens_issues_by_patient_id(patient_id) + + @router.post( "/", response_model=LensIssueEntity, diff --git a/api/app/infrastructure/lens_issues_service.py b/api/app/infrastructure/lens_issues_service.py index 9f95552..a2da72a 100644 --- a/api/app/infrastructure/lens_issues_service.py +++ b/api/app/infrastructure/lens_issues_service.py @@ -24,13 +24,13 @@ class LensIssuesService: self.lenses_repository = LensesRepository(db) async def get_all_lens_issues( - self, - skip: int = 0, - limit: int = 10, - search: Optional[str] = None, - sort_order: Literal["asc", "desc"] = "desc", - start_date: Optional[date] = None, - end_date: Optional[date] = None + self, + skip: int = 0, + limit: int = 10, + search: Optional[str] = None, + sort_order: Literal["asc", "desc"] = "desc", + start_date: Optional[date] = None, + end_date: Optional[date] = None ) -> Tuple[list[LensIssueEntity], int]: lens_issues, total_count = await self.lens_issues_repository.get_all( skip=skip, @@ -45,6 +45,24 @@ class LensIssuesService: total_count ) + async def get_lens_issues_by_patient_id(self, patient_id: int) -> list[LensIssueEntity]: + patient = await self.patient_repository.get_by_id(patient_id) + + if not patient: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail='Пациент с таким ID не найден', + ) + + lens_issues = await self.lens_issues_repository.get_by_patient_id(patient.id) + + print(lens_issues) + + return [ + self.model_to_entity(lens_issue) + for lens_issue in lens_issues + ] + async def create_lens_issue(self, lens_issue: LensIssueEntity, user_id: int) -> Optional[LensIssueEntity]: patient = await self.patient_repository.get_by_id(lens_issue.patient_id) diff --git a/web-app/src/Api/lensIssuesApi.js b/web-app/src/Api/lensIssuesApi.js index 0180363..c6773fd 100644 --- a/web-app/src/Api/lensIssuesApi.js +++ b/web-app/src/Api/lensIssuesApi.js @@ -1,5 +1,5 @@ -import { createApi } from "@reduxjs/toolkit/query/react"; -import { baseQueryWithAuth } from "./baseQuery.js"; +import {createApi} from "@reduxjs/toolkit/query/react"; +import {baseQueryWithAuth} from "./baseQuery.js"; export const lensIssuesApi = createApi({ reducerPath: 'lensIssuesApi', @@ -7,7 +7,7 @@ export const lensIssuesApi = createApi({ tagTypes: ['LensIssues'], endpoints: (builder) => ({ getLensIssues: builder.query({ - query: ({ page, pageSize, search, sortOrder, startDate, endDate }) => ({ + query: ({page, pageSize, search, sortOrder, startDate, endDate}) => ({ url: '/lens_issues/', params: { page, @@ -22,16 +22,16 @@ export const lensIssuesApi = createApi({ transformResponse: (response) => { if (!response) { console.warn('Empty lens issues API response:', response); - return { issues: [], total_count: 0 }; + return {issues: [], total_count: 0}; } if (Array.isArray(response.results) && typeof response.count === 'number') { - return { issues: response.results, total_count: response.count }; + return {issues: response.results, total_count: response.count}; } if (Array.isArray(response.issues) && typeof response.total_count === 'number') { return response; } console.warn('Unexpected lens issues API response:', response); - return { issues: [], total_count: 0 }; + return {issues: [], total_count: 0}; }, transformErrorResponse: (response) => { console.error('Lens issues API error:', response); @@ -46,10 +46,15 @@ export const lensIssuesApi = createApi({ }), invalidatesTags: ['LensIssues'], }), + getLensIssuesByPatient: builder.query({ + query: (patientId) => `/lens_issues/by-patient/${patientId}/`, + providesTags: ['LensIssues'], + }), }), }); export const { useGetLensIssuesQuery, useAddLensIssuesMutation, + useGetLensIssuesByPatientQuery, } = lensIssuesApi; \ No newline at end of file diff --git a/web-app/src/Components/Dummies/PatientFormModal/usePatientFormModal.js b/web-app/src/Components/Dummies/PatientFormModal/usePatientFormModal.js index e3ff1fc..154b44f 100644 --- a/web-app/src/Components/Dummies/PatientFormModal/usePatientFormModal.js +++ b/web-app/src/Components/Dummies/PatientFormModal/usePatientFormModal.js @@ -7,8 +7,8 @@ import {useAddPatientMutation, useUpdatePatientMutation} from "../../../Api/pati const usePatientFormModal = () => { const dispatch = useDispatch(); - const [addPatient, { isLoading: isAdding }] = useAddPatientMutation(); - const [updatePatient, { isLoading: isUpdating }] = useUpdatePatientMutation(); + const [addPatient, {isLoading: isAdding}] = useAddPatientMutation(); + const [updatePatient, {isLoading: isUpdating}] = useUpdatePatientMutation(); const { selectedPatient, @@ -19,7 +19,7 @@ const usePatientFormModal = () => { try { if (selectedPatient) { - await updatePatient({ id: selectedPatient.id, ...patientData }).unwrap(); + await updatePatient({id: selectedPatient.id, ...patientData}).unwrap(); notification.success({ message: "Пациент обновлён", description: `Данные пациента ${patientData.first_name} ${patientData.last_name} успешно обновлены.`, diff --git a/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/usePatientsViewModal.js b/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/usePatientsViewModal.js new file mode 100644 index 0000000..54d2582 --- /dev/null +++ b/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/usePatientsViewModal.js @@ -0,0 +1,21 @@ +import { useGetLensIssuesByPatientQuery } from "../../../../../Api/lensIssuesApi.js"; + +const usePatientsViewModal = (patient, visible) => { + const { + data: lensIssues = [], + isLoading: isLensIssuesLoading, + isError: isLensIssuesError, + } = useGetLensIssuesByPatientQuery(patient?.id, { + skip: !visible || !patient?.id, + pollingInterval: 60000, + refetchOnMountOrArgChange: true, + }); + + return { + lensIssues, + isLensIssuesLoading, + isLensIssuesError, + }; +}; + +export default usePatientsViewModal; \ No newline at end of file