feat: Добавлен запрос истории линз по пациенту

Добавлен API endpoint и query для получения истории линз по ID пациента.
This commit is contained in:
Андрей Дувакин 2025-07-04 07:06:57 +05:00
parent 12eea23299
commit 1541aba89f
7 changed files with 112 additions and 32 deletions

View File

@ -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 .

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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} успешно обновлены.`,

View File

@ -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;