From 551af24be9de4cad8915f79767f8395989ea70de Mon Sep 17 00:00:00 2001 From: andrei Date: Fri, 4 Jul 2025 07:35:20 +0500 Subject: [PATCH] =?UTF-8?q?feat:=20lensIssues=20-=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC?= =?UTF-8?q?=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20lensIssue=20=D0=BF=D0=BE?= =?UTF-8?q?=20lensId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/application/lens_issues_repository.py | 9 +++ api/app/controllers/lens_issues_router.py | 15 ++++ api/app/infrastructure/lens_issues_service.py | 17 +++- web-app/src/Api/lensIssuesApi.js | 5 ++ .../LensViewModal/useLensViewModal.js | 22 ++++++ .../PatientViewModal/PatientViewModal.jsx | 78 ++++++++++++++++--- 6 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 web-app/src/Components/Pages/LensesSetsPage/Components/LensesTab/Components/LensViewModal/useLensViewModal.js diff --git a/api/app/application/lens_issues_repository.py b/api/app/application/lens_issues_repository.py index 97f3f94..2137500 100644 --- a/api/app/application/lens_issues_repository.py +++ b/api/app/application/lens_issues_repository.py @@ -85,6 +85,15 @@ class LensIssuesRepository: result = await self.db.execute(stmt) return result.scalars().all() + async def get_by_lens_id(self, lens_id: int) -> Optional[LensIssue]: + stmt = ( + select(LensIssue) + .filter_by(lens_id=lens_id) + .options(joinedload(LensIssue.patient)) + ) + result = await self.db.execute(stmt) + return result.scalars().first() + 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 f2ab7f4..3cd4992 100644 --- a/api/app/controllers/lens_issues_router.py +++ b/api/app/controllers/lens_issues_router.py @@ -60,6 +60,21 @@ async def get_lens_issues_by_patient( return await lens_issues_service.get_lens_issues_by_patient_id(patient_id) +@router.get( + '/by-lens/{lens_id}/', + response_model=Optional[LensIssueEntity], + summary="Get lens issues by lens id", + description="Returns a paginated list of lens issues by lens id", +) +async def get_lens_issues_by_lens_id( + lens_id: int, + db: AsyncSession = Depends(get_db), + user=Depends(get_current_user), +): + lens_issues_service = LensIssuesService(db) + return await lens_issues_service.get_lens_issue_by_lens_id(lens_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 a2da72a..0a77d81 100644 --- a/api/app/infrastructure/lens_issues_service.py +++ b/api/app/infrastructure/lens_issues_service.py @@ -1,5 +1,5 @@ from datetime import date -from typing import Optional, Literal, Tuple +from typing import Optional, Literal, Tuple, Any, Coroutine from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession @@ -56,13 +56,24 @@ class LensIssuesService: 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 get_lens_issue_by_lens_id(self, lens_id: int) -> Optional[LensIssueEntity]: + lens = await self.lenses_repository.get_by_id(lens_id) + + if not lens: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail='Линза с таким ID не найдена', + ) + + lens_issue = await self.lens_issues_repository.get_by_lens_id(lens_id) + + return self.model_to_entity(lens_issue) + 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 c6773fd..7583e17 100644 --- a/web-app/src/Api/lensIssuesApi.js +++ b/web-app/src/Api/lensIssuesApi.js @@ -50,6 +50,10 @@ export const lensIssuesApi = createApi({ query: (patientId) => `/lens_issues/by-patient/${patientId}/`, providesTags: ['LensIssues'], }), + getLensIssueByLens: builder.query({ + query: (lensId) => `/lens_issues/by-lens/${lensId}/`, + providesTags: ['LensIssues'], + }), }), }); @@ -57,4 +61,5 @@ export const { useGetLensIssuesQuery, useAddLensIssuesMutation, useGetLensIssuesByPatientQuery, + useGetLensIssueByLensQuery, } = lensIssuesApi; \ No newline at end of file diff --git a/web-app/src/Components/Pages/LensesSetsPage/Components/LensesTab/Components/LensViewModal/useLensViewModal.js b/web-app/src/Components/Pages/LensesSetsPage/Components/LensesTab/Components/LensViewModal/useLensViewModal.js new file mode 100644 index 0000000..166df87 --- /dev/null +++ b/web-app/src/Components/Pages/LensesSetsPage/Components/LensesTab/Components/LensViewModal/useLensViewModal.js @@ -0,0 +1,22 @@ +import {useGetLensIssueByLensQuery} from "../../../../../../../Api/lensIssuesApi.js"; + + +const useLensViewModal = (lens, visible) => { + const { + data: lensIssue = null, + isLoading: isLensIssueLoading, + isError: isLensIssueError, + } = useGetLensIssueByLensQuery(lens?.id, { + skip: !visible || !lens?.id, + pollingInterval: 60000, + refetchOnMountOrArgChange: true, + }); + + return { + lensIssue, + isLensIssueLoading, + isLensIssueError, + }; +}; + +export default useLensViewModal; \ No newline at end of file diff --git a/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/PatientViewModal.jsx b/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/PatientViewModal.jsx index ae8927a..052d015 100644 --- a/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/PatientViewModal.jsx +++ b/web-app/src/Components/Pages/PatientsPage/Components/PatientViewModal/PatientViewModal.jsx @@ -1,10 +1,61 @@ -import {Button, Col, Modal, Row, Typography, Divider} from "antd"; +import {Button, Col, Modal, Row, Typography, Divider, Collapse, Result} from "antd"; import PropTypes from "prop-types"; import {PatientPropType} from "../../../../../Types/patientPropType.js"; +import usePatientsViewModal from "./usePatientsViewModal.js"; +import LoadingIndicator from "../../../../Widgets/LoadingIndicator/LoadingIndicator.jsx"; + +const {Text, Title} = Typography; + +const PatientViewModal = ({visible, onCancel, patient}) => { + const {lensIssues, isLensIssuesLoading, isLensIssuesError} = usePatientsViewModal(patient, visible); + + if (isLensIssuesLoading) { + return ( + + + + ); + } + + if (isLensIssuesError) { + return ( + + Закрыть} + /> + + ); + } + + const items = lensIssues.length ? lensIssues.map((issue) => { + return { + key: issue.id, + label: `${new Date(issue.issue_date).toLocaleDateString('ru-RU')}`, + children: issue.lens ? ( +
+

id: {issue.lens.id}

+

Линза: {issue.lens.side}

+

Диаметр: {issue.lens.diameter}

+

Тор: {issue.lens.tor}

+

Пресетная рефракция: {issue.lens.preset_refraction}

+

Периферийная торичность: {issue.lens.periphery_toricity}

+

FVC: {issue.lens.fvc}

+

ESP: {issue.lens.esa}

+
+ ) : ( +

Данные о линзе отсутствуют

+ ), + }; + }) : [{ + key: 'no-lenses', + label: 'Нет выданных линз', + children:

У пациента нет выданных линз

, + }]; -const { Text, Title } = Typography; -const PatientViewModal = ({ visible, onCancel, patient }) => { return ( { > -
+
👤 ФИО {`${patient.last_name} ${patient.first_name} ${patient.patronymic || ''}`}
-
+
🎂 Дата рождения {new Date(patient.birthday).toLocaleDateString('ru-RU', { @@ -36,34 +87,39 @@ const PatientViewModal = ({ visible, onCancel, patient }) => { -
+
📞 Телефон {patient.phone || 'Не указан'}
-
+
✉️ Email {patient.email || 'Не указан'}
-
+
🏠 Адрес {patient.address || 'Не указан'}
- + -
+
🩺 Диагноз {patient.diagnosis || 'Не указан'}
-
+
👓 Коррекция {patient.correction || 'Не указ'}
+ + 📦 Выданные линзы + ); };