feat: Добавлена поддержка предстоящих приемов
This commit is contained in:
parent
3a22fd05be
commit
c609c6471d
@ -1,5 +1,5 @@
|
|||||||
from typing import Sequence, Optional
|
from typing import Sequence, Optional
|
||||||
from sqlalchemy import select, desc
|
from sqlalchemy import select, desc, func
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from datetime import date
|
from datetime import date
|
||||||
@ -27,7 +27,7 @@ class AppointmentsRepository:
|
|||||||
return result.scalars().all()
|
return result.scalars().all()
|
||||||
|
|
||||||
async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
||||||
Sequence[Appointment]:
|
Sequence[Appointment]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(Appointment)
|
select(Appointment)
|
||||||
.options(joinedload(Appointment.type))
|
.options(joinedload(Appointment.type))
|
||||||
@ -43,8 +43,22 @@ class AppointmentsRepository:
|
|||||||
result = await self.db.execute(stmt)
|
result = await self.db.execute(stmt)
|
||||||
return result.scalars().all()
|
return result.scalars().all()
|
||||||
|
|
||||||
|
async def get_upcoming_by_doctor_id(self, doctor_id: int) -> Sequence[Appointment]:
|
||||||
|
stmt = (
|
||||||
|
select(Appointment)
|
||||||
|
.options(joinedload(Appointment.type))
|
||||||
|
.options(joinedload(Appointment.patient))
|
||||||
|
.options(joinedload(Appointment.doctor))
|
||||||
|
.filter_by(doctor_id=doctor_id)
|
||||||
|
.filter(Appointment.appointment_datetime >= func.now())
|
||||||
|
.order_by(Appointment.appointment_datetime)
|
||||||
|
.limit(5)
|
||||||
|
)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
return result.scalars().all()
|
||||||
|
|
||||||
async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
||||||
Sequence[Appointment]:
|
Sequence[Appointment]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(Appointment)
|
select(Appointment)
|
||||||
.options(joinedload(Appointment.type))
|
.options(joinedload(Appointment.type))
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
from sqlalchemy import select, desc
|
from sqlalchemy import select, desc, func
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from datetime import date
|
from datetime import date
|
||||||
@ -29,7 +29,7 @@ class ScheduledAppointmentsRepository:
|
|||||||
return result.scalars().all()
|
return result.scalars().all()
|
||||||
|
|
||||||
async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
async def get_by_doctor_id(self, doctor_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
||||||
Sequence[ScheduledAppointment]:
|
Sequence[ScheduledAppointment]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(ScheduledAppointment)
|
select(ScheduledAppointment)
|
||||||
.options(joinedload(ScheduledAppointment.type))
|
.options(joinedload(ScheduledAppointment.type))
|
||||||
@ -45,8 +45,22 @@ class ScheduledAppointmentsRepository:
|
|||||||
result = await self.db.execute(stmt)
|
result = await self.db.execute(stmt)
|
||||||
return result.scalars().all()
|
return result.scalars().all()
|
||||||
|
|
||||||
|
async def get_upcoming_by_doctor_id(self, doctor_id: int) -> Sequence[ScheduledAppointment]:
|
||||||
|
stmt = (
|
||||||
|
select(ScheduledAppointment)
|
||||||
|
.options(joinedload(ScheduledAppointment.type))
|
||||||
|
.options(joinedload(ScheduledAppointment.patient))
|
||||||
|
.options(joinedload(ScheduledAppointment.doctor))
|
||||||
|
.filter_by(doctor_id=doctor_id, is_canceled=False)
|
||||||
|
.filter(ScheduledAppointment.scheduled_datetime >= func.now())
|
||||||
|
.order_by(ScheduledAppointment.scheduled_datetime)
|
||||||
|
.limit(5)
|
||||||
|
)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
return result.scalars().all()
|
||||||
|
|
||||||
async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
async def get_by_patient_id(self, patient_id: int, start_date: date | None = None, end_date: date | None = None) -> \
|
||||||
Sequence[ScheduledAppointment]:
|
Sequence[ScheduledAppointment]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(ScheduledAppointment)
|
select(ScheduledAppointment)
|
||||||
.options(joinedload(ScheduledAppointment.type))
|
.options(joinedload(ScheduledAppointment.type))
|
||||||
|
|||||||
@ -43,6 +43,21 @@ async def get_all_appointments_by_doctor_id(
|
|||||||
return await appointments_service.get_appointments_by_doctor_id(doctor_id, start_date=start_date, end_date=end_date)
|
return await appointments_service.get_appointments_by_doctor_id(doctor_id, start_date=start_date, end_date=end_date)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/doctor/{doctor_id}/upcoming/",
|
||||||
|
response_model=list[AppointmentEntity],
|
||||||
|
summary="Get upcoming appointments for doctor",
|
||||||
|
description="Returns the next 5 upcoming appointments for doctor",
|
||||||
|
)
|
||||||
|
async def get_upcoming_appointments_by_doctor_id(
|
||||||
|
doctor_id: int,
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
appointments_service = AppointmentsService(db)
|
||||||
|
return await appointments_service.get_upcoming_appointments_by_doctor_id(doctor_id)
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/patient/{patient_id}/",
|
"/patient/{patient_id}/",
|
||||||
response_model=list[AppointmentEntity],
|
response_model=list[AppointmentEntity],
|
||||||
|
|||||||
@ -45,6 +45,21 @@ async def get_all_scheduled_appointments_by_doctor_id(
|
|||||||
end_date=end_date)
|
end_date=end_date)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/doctor/{doctor_id}/upcoming/",
|
||||||
|
response_model=list[ScheduledAppointmentEntity],
|
||||||
|
summary="Get upcoming scheduled appointments for doctor",
|
||||||
|
description="Returns the next 5 upcoming scheduled appointments for doctor",
|
||||||
|
)
|
||||||
|
async def get_upcoming_scheduled_appointments_by_doctor_id(
|
||||||
|
doctor_id: int,
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
appointments_service = ScheduledAppointmentsService(db)
|
||||||
|
return await appointments_service.get_upcoming_scheduled_appointments_by_doctor_id(doctor_id)
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/patient/{patient_id}/",
|
"/patient/{patient_id}/",
|
||||||
response_model=ScheduledAppointmentEntity,
|
response_model=ScheduledAppointmentEntity,
|
||||||
|
|||||||
@ -39,6 +39,16 @@ class AppointmentsService:
|
|||||||
end_date=end_date)
|
end_date=end_date)
|
||||||
return [self.model_to_entity(appointment) for appointment in appointments]
|
return [self.model_to_entity(appointment) for appointment in appointments]
|
||||||
|
|
||||||
|
async def get_upcoming_appointments_by_doctor_id(self, doctor_id: int) -> Optional[list[AppointmentEntity]]:
|
||||||
|
doctor = await self.users_repository.get_by_id(doctor_id)
|
||||||
|
if not doctor:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail='Доктор с таким ID не найден',
|
||||||
|
)
|
||||||
|
appointments = await self.appointments_repository.get_upcoming_by_doctor_id(doctor_id)
|
||||||
|
return [self.model_to_entity(appointment) for appointment in appointments]
|
||||||
|
|
||||||
async def get_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None,
|
async def get_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None,
|
||||||
end_date: date | None = None) -> Optional[list[AppointmentEntity]]:
|
end_date: date | None = None) -> Optional[list[AppointmentEntity]]:
|
||||||
patient = await self.patients_repository.get_by_id(patient_id)
|
patient = await self.patients_repository.get_by_id(patient_id)
|
||||||
|
|||||||
@ -39,6 +39,17 @@ class ScheduledAppointmentsService:
|
|||||||
end_date=end_date)
|
end_date=end_date)
|
||||||
return [self.model_to_entity(scheduled_appointment) for scheduled_appointment in scheduled_appointments]
|
return [self.model_to_entity(scheduled_appointment) for scheduled_appointment in scheduled_appointments]
|
||||||
|
|
||||||
|
async def get_upcoming_scheduled_appointments_by_doctor_id(self, doctor_id: int) -> Optional[
|
||||||
|
list[ScheduledAppointmentEntity]]:
|
||||||
|
doctor = await self.users_repository.get_by_id(doctor_id)
|
||||||
|
if not doctor:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail='Доктор с таким ID не найден',
|
||||||
|
)
|
||||||
|
scheduled_appointments = await self.scheduled_appointment_repository.get_upcoming_by_doctor_id(doctor_id)
|
||||||
|
return [self.model_to_entity(scheduled_appointment) for scheduled_appointment in scheduled_appointments]
|
||||||
|
|
||||||
async def get_scheduled_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None,
|
async def get_scheduled_appointments_by_patient_id(self, patient_id: int, start_date: date | None = None,
|
||||||
end_date: date | None = None) -> Optional[
|
end_date: date | None = None) -> Optional[
|
||||||
list[ScheduledAppointmentEntity]]:
|
list[ScheduledAppointmentEntity]]:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
import {createApi} from "@reduxjs/toolkit/query/react";
|
||||||
import { baseQueryWithAuth } from "./baseQuery.js";
|
import {baseQueryWithAuth} from "./baseQuery.js";
|
||||||
|
|
||||||
export const appointmentsApi = createApi({
|
export const appointmentsApi = createApi({
|
||||||
reducerPath: 'appointmentsApi',
|
reducerPath: 'appointmentsApi',
|
||||||
@ -7,13 +7,17 @@ export const appointmentsApi = createApi({
|
|||||||
tagTypes: ['Appointment'],
|
tagTypes: ['Appointment'],
|
||||||
endpoints: (builder) => ({
|
endpoints: (builder) => ({
|
||||||
getAppointments: builder.query({
|
getAppointments: builder.query({
|
||||||
query: ({ doctor_id, start_date, end_date }) => ({
|
query: ({doctor_id, start_date, end_date}) => ({
|
||||||
url: `/appointments/doctor/${doctor_id}/`,
|
url: `/appointments/doctor/${doctor_id}/`,
|
||||||
params: { start_date, end_date },
|
params: {start_date, end_date},
|
||||||
}),
|
}),
|
||||||
providesTags: ['Appointment'],
|
providesTags: ['Appointment'],
|
||||||
refetchOnMountOrArgChange: 5,
|
refetchOnMountOrArgChange: 5,
|
||||||
}),
|
}),
|
||||||
|
getUpcomingAppointments: builder.query({
|
||||||
|
query: (doctor_id) => `/appointments/doctor/${doctor_id}/upcoming/`,
|
||||||
|
providesTags: ['Appointment'],
|
||||||
|
}),
|
||||||
getByPatientId: builder.query({
|
getByPatientId: builder.query({
|
||||||
query: (id) => `/appointments/patient/${id}/`,
|
query: (id) => `/appointments/patient/${id}/`,
|
||||||
providesTags: ['Appointment'],
|
providesTags: ['Appointment'],
|
||||||
@ -28,7 +32,7 @@ export const appointmentsApi = createApi({
|
|||||||
invalidatesTags: ['Appointment'],
|
invalidatesTags: ['Appointment'],
|
||||||
}),
|
}),
|
||||||
updateAppointment: builder.mutation({
|
updateAppointment: builder.mutation({
|
||||||
query: ({ id, data }) => ({
|
query: ({id, data}) => ({
|
||||||
url: `/appointments/${id}/`,
|
url: `/appointments/${id}/`,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: data,
|
body: data,
|
||||||
@ -40,6 +44,7 @@ export const appointmentsApi = createApi({
|
|||||||
|
|
||||||
export const {
|
export const {
|
||||||
useGetAppointmentsQuery,
|
useGetAppointmentsQuery,
|
||||||
|
useGetUpcomingAppointmentsQuery,
|
||||||
useGetByPatientIdQuery,
|
useGetByPatientIdQuery,
|
||||||
useCreateAppointmentMutation,
|
useCreateAppointmentMutation,
|
||||||
useUpdateAppointmentMutation,
|
useUpdateAppointmentMutation,
|
||||||
|
|||||||
@ -13,6 +13,10 @@ export const scheduledAppointmentsApi = createApi({
|
|||||||
}),
|
}),
|
||||||
providesTags: ['ScheduledAppointment'],
|
providesTags: ['ScheduledAppointment'],
|
||||||
}),
|
}),
|
||||||
|
getUpcomingScheduledAppointments: builder.query({
|
||||||
|
query: (doctor_id) => `/scheduled_appointments/doctor/${doctor_id}/upcoming/`,
|
||||||
|
providesTags: ['ScheduledAppointment'],
|
||||||
|
}),
|
||||||
createScheduledAppointment: builder.mutation({
|
createScheduledAppointment: builder.mutation({
|
||||||
query: (data) => ({
|
query: (data) => ({
|
||||||
url: '/scheduled_appointments/',
|
url: '/scheduled_appointments/',
|
||||||
@ -41,6 +45,7 @@ export const scheduledAppointmentsApi = createApi({
|
|||||||
|
|
||||||
export const {
|
export const {
|
||||||
useGetScheduledAppointmentsQuery,
|
useGetScheduledAppointmentsQuery,
|
||||||
|
useGetUpcomingScheduledAppointmentsQuery,
|
||||||
useCreateScheduledAppointmentMutation,
|
useCreateScheduledAppointmentMutation,
|
||||||
useUpdateScheduledAppointmentMutation,
|
useUpdateScheduledAppointmentMutation,
|
||||||
useCancelScheduledAppointmentMutation,
|
useCancelScheduledAppointmentMutation,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {Badge, Button, FloatButton, List, Result, Row, Space, Tag, Typography} from "antd";
|
import { Badge, Button, FloatButton, List, Result, Row, Space, Tag, Typography } from "antd";
|
||||||
import {Splitter} from "antd";
|
import { Splitter } from "antd";
|
||||||
import {
|
import {
|
||||||
CalendarOutlined,
|
CalendarOutlined,
|
||||||
MenuFoldOutlined,
|
MenuFoldOutlined,
|
||||||
@ -13,14 +13,15 @@ import dayjs from 'dayjs';
|
|||||||
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||||
import AppointmentFormModal from "../../Dummies/AppointmentFormModal/AppointmentFormModal.jsx";
|
import AppointmentFormModal from "../../Dummies/AppointmentFormModal/AppointmentFormModal.jsx";
|
||||||
import AppointmentViewModal from "../../Dummies/AppointmentViewModal/AppointmentViewModal.jsx";
|
import AppointmentViewModal from "../../Dummies/AppointmentViewModal/AppointmentViewModal.jsx";
|
||||||
import ScheduledAppointmentFormModal
|
import ScheduledAppointmentFormModal from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.jsx";
|
||||||
from "../../Dummies/ScheduledAppintmentFormModal/ScheduledAppointmentFormModal.jsx";
|
import ScheduledAppointmentsViewModal from "../../Widgets/ScheduledAppointmentsViewModal/ScheduledAppointmentsViewModal.jsx";
|
||||||
import ScheduledAppointmentsViewModal
|
|
||||||
from "../../Widgets/ScheduledAppointmentsViewModal/ScheduledAppointmentsViewModal.jsx";
|
|
||||||
import AppointmentsListModal from "./Components/AppointmentsListModal/AppointmentsListModal.jsx";
|
import AppointmentsListModal from "./Components/AppointmentsListModal/AppointmentsListModal.jsx";
|
||||||
|
|
||||||
const AppointmentsPage = () => {
|
const AppointmentsPage = () => {
|
||||||
const {
|
const {
|
||||||
|
patients, // Добавляем
|
||||||
|
appointments, // Добавляем
|
||||||
|
scheduledAppointments, // Добавляем
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
collapsed,
|
collapsed,
|
||||||
@ -46,7 +47,6 @@ const AppointmentsPage = () => {
|
|||||||
openCreateAppointmentModal,
|
openCreateAppointmentModal,
|
||||||
} = useAppointments();
|
} = useAppointments();
|
||||||
|
|
||||||
|
|
||||||
if (isError) return (
|
if (isError) return (
|
||||||
<Result
|
<Result
|
||||||
status="error"
|
status="error"
|
||||||
@ -57,30 +57,20 @@ const AppointmentsPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography.Title level={1}><CalendarOutlined/> Приемы</Typography.Title>
|
<Typography.Title level={1}><CalendarOutlined /> Приемы</Typography.Title>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<LoadingIndicator/>
|
<LoadingIndicator />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Row justify="end" style={{marginBottom: 10, marginRight: "2.4rem"}}>
|
<Row justify="end" style={{ marginBottom: 10, marginRight: "2.4rem" }}>
|
||||||
<Space direction={"vertical"}>
|
<Space direction={"vertical"}>
|
||||||
<Tag color={"blue"} style={{width: "100%"}}>
|
<Tag color={"blue"} style={{ width: "100%" }}>
|
||||||
<Badge status={"processing"}
|
<Badge status={"processing"}
|
||||||
text={
|
text={<span style={badgeTextStyle}>Запланированный прием</span>} />
|
||||||
<span style={badgeTextStyle}>
|
|
||||||
Запланированный прием
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Tag>
|
</Tag>
|
||||||
<Tag color={"green"} style={{width: "100%"}}>
|
<Tag color={"green"} style={{ width: "100%" }}>
|
||||||
<Badge status={"success"}
|
<Badge status={"success"}
|
||||||
text={
|
text={<span style={badgeTextStyle}>Прошедший прием</span>} />
|
||||||
<span style={badgeTextStyle}>
|
|
||||||
Прошедший прием
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Tag>
|
</Tag>
|
||||||
</Space>
|
</Space>
|
||||||
</Row>
|
</Row>
|
||||||
@ -100,9 +90,10 @@ const AppointmentsPage = () => {
|
|||||||
<AppointmentsCalendarTab
|
<AppointmentsCalendarTab
|
||||||
currentMonth={currentMonth}
|
currentMonth={currentMonth}
|
||||||
onMonthChange={handleMonthChange}
|
onMonthChange={handleMonthChange}
|
||||||
|
appointments={appointments} // Добавляем
|
||||||
|
scheduledAppointments={scheduledAppointments} // Добавляем
|
||||||
/>
|
/>
|
||||||
</Splitter.Panel>
|
</Splitter.Panel>
|
||||||
|
|
||||||
{showSplitterPanel && (
|
{showSplitterPanel && (
|
||||||
<Splitter.Panel
|
<Splitter.Panel
|
||||||
style={splitterSiderPanelStyle}
|
style={splitterSiderPanelStyle}
|
||||||
@ -118,8 +109,7 @@ const AppointmentsPage = () => {
|
|||||||
dataSource={upcomingEvents.sort((a, b) =>
|
dataSource={upcomingEvents.sort((a, b) =>
|
||||||
dayjs(a.appointment_datetime || a.scheduled_datetime).diff(
|
dayjs(a.appointment_datetime || a.scheduled_datetime).diff(
|
||||||
dayjs(b.appointment_datetime || b.scheduled_datetime)
|
dayjs(b.appointment_datetime || b.scheduled_datetime)
|
||||||
)
|
))}
|
||||||
)}
|
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item
|
<List.Item
|
||||||
onClick={() => handleEventClick(item)}
|
onClick={() => handleEventClick(item)}
|
||||||
@ -137,9 +127,9 @@ const AppointmentsPage = () => {
|
|||||||
<Space direction="vertical" size={2}>
|
<Space direction="vertical" size={2}>
|
||||||
<Space>
|
<Space>
|
||||||
{item.appointment_datetime ? (
|
{item.appointment_datetime ? (
|
||||||
<ClockCircleOutlined style={{color: "#52c41a"}}/>
|
<ClockCircleOutlined style={{ color: "#52c41a" }} />
|
||||||
) : (
|
) : (
|
||||||
<CalendarOutlined style={{color: "#1890ff"}}/>
|
<CalendarOutlined style={{ color: "#1890ff" }} />
|
||||||
)}
|
)}
|
||||||
<Typography.Text strong>
|
<Typography.Text strong>
|
||||||
{dayjs(item.appointment_datetime || item.scheduled_datetime).format('DD.MM.YYYY HH:mm')}
|
{dayjs(item.appointment_datetime || item.scheduled_datetime).format('DD.MM.YYYY HH:mm')}
|
||||||
@ -173,7 +163,7 @@ const AppointmentsPage = () => {
|
|||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={handleToggleSider}
|
onClick={handleToggleSider}
|
||||||
icon={collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/>}
|
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
||||||
style={siderButtonStyle}
|
style={siderButtonStyle}
|
||||||
>
|
>
|
||||||
{siderButtonText}
|
{siderButtonText}
|
||||||
@ -183,26 +173,26 @@ const AppointmentsPage = () => {
|
|||||||
placement={"left"}
|
placement={"left"}
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<PlusOutlined/>}
|
icon={<PlusOutlined />}
|
||||||
tooltip="Создать"
|
tooltip="Создать"
|
||||||
>
|
>
|
||||||
<FloatButton
|
<FloatButton
|
||||||
icon={<PlusOutlined/>}
|
icon={<PlusOutlined />}
|
||||||
onClick={openCreateAppointmentModal}
|
onClick={openCreateAppointmentModal}
|
||||||
tooltip="Прием"
|
tooltip="Прием"
|
||||||
/>
|
/>
|
||||||
<FloatButton
|
<FloatButton
|
||||||
icon={<CalendarOutlined/>}
|
icon={<CalendarOutlined />}
|
||||||
onClick={openCreateScheduledAppointmentModal}
|
onClick={openCreateScheduledAppointmentModal}
|
||||||
tooltip="Запланированный прием"
|
tooltip="Запланированный прием"
|
||||||
/>
|
/>
|
||||||
</FloatButton.Group>
|
</FloatButton.Group>
|
||||||
|
|
||||||
<AppointmentFormModal/>
|
<AppointmentFormModal />
|
||||||
<AppointmentViewModal/>
|
<AppointmentViewModal />
|
||||||
<ScheduledAppointmentFormModal/>
|
<ScheduledAppointmentFormModal />
|
||||||
<ScheduledAppointmentsViewModal/>
|
<ScheduledAppointmentsViewModal />
|
||||||
<AppointmentsListModal/>
|
<AppointmentsListModal />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { notification } from "antd";
|
|||||||
import { Grid } from "antd";
|
import { Grid } from "antd";
|
||||||
import {
|
import {
|
||||||
useGetAppointmentsQuery,
|
useGetAppointmentsQuery,
|
||||||
|
useGetUpcomingAppointmentsQuery,
|
||||||
} from "../../../Api/appointmentsApi.js";
|
} from "../../../Api/appointmentsApi.js";
|
||||||
import { useGetAllPatientsQuery } from "../../../Api/patientsApi.js";
|
import { useGetAllPatientsQuery } from "../../../Api/patientsApi.js";
|
||||||
import {
|
import {
|
||||||
@ -14,8 +15,17 @@ import {
|
|||||||
setSelectedScheduledAppointment,
|
setSelectedScheduledAppointment,
|
||||||
toggleSider
|
toggleSider
|
||||||
} from "../../../Redux/Slices/appointmentsSlice.js";
|
} from "../../../Redux/Slices/appointmentsSlice.js";
|
||||||
import { useGetScheduledAppointmentsQuery } from "../../../Api/scheduledAppointmentsApi.js";
|
import {
|
||||||
|
useGetScheduledAppointmentsQuery,
|
||||||
|
useGetUpcomingScheduledAppointmentsQuery,
|
||||||
|
} from "../../../Api/scheduledAppointmentsApi.js";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import utc from "dayjs/plugin/utc";
|
||||||
|
import timezone from "dayjs/plugin/timezone";
|
||||||
|
|
||||||
|
dayjs.extend(utc);
|
||||||
|
dayjs.extend(timezone);
|
||||||
|
dayjs.tz.setDefault("Europe/Moscow");
|
||||||
|
|
||||||
const { useBreakpoint } = Grid;
|
const { useBreakpoint } = Grid;
|
||||||
|
|
||||||
@ -25,13 +35,13 @@ const useAppointments = () => {
|
|||||||
const { collapsed, siderWidth, hovered, selectedAppointment } = useSelector(state => state.appointmentsUI);
|
const { collapsed, siderWidth, hovered, selectedAppointment } = useSelector(state => state.appointmentsUI);
|
||||||
const screens = useBreakpoint();
|
const screens = useBreakpoint();
|
||||||
|
|
||||||
const [currentMonth, setCurrentMonth] = useState(dayjs().startOf('month'));
|
const [currentMonth, setCurrentMonth] = useState(dayjs().tz("Europe/Moscow").startOf('month'));
|
||||||
|
|
||||||
const startDate = currentMonth.startOf('month').format('YYYY-MM-DD');
|
const startDate = currentMonth.startOf('month').tz("Europe/Moscow").format('YYYY-MM-DD');
|
||||||
const endDate = currentMonth.endOf('month').format('YYYY-MM-DD');
|
const endDate = currentMonth.endOf('month').tz("Europe/Moscow").format('YYYY-MM-DD');
|
||||||
|
|
||||||
const handleMonthChange = (newMonth) => {
|
const handleMonthChange = (newMonth) => {
|
||||||
setCurrentMonth(dayjs(newMonth).startOf('month'));
|
setCurrentMonth(dayjs(newMonth).tz("Europe/Moscow").startOf('month'));
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -39,7 +49,8 @@ const useAppointments = () => {
|
|||||||
isLoading: isLoadingAppointments,
|
isLoading: isLoadingAppointments,
|
||||||
isError: isErrorAppointments,
|
isError: isErrorAppointments,
|
||||||
} = useGetAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, {
|
} = useGetAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, {
|
||||||
pollingInterval: 20000,
|
pollingInterval: 60000,
|
||||||
|
skip: !userData.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -47,7 +58,8 @@ const useAppointments = () => {
|
|||||||
isLoading: isLoadingScheduledAppointments,
|
isLoading: isLoadingScheduledAppointments,
|
||||||
isError: isErrorScheduledAppointments,
|
isError: isErrorScheduledAppointments,
|
||||||
} = useGetScheduledAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, {
|
} = useGetScheduledAppointmentsQuery({ doctor_id: userData.id, start_date: startDate, end_date: endDate }, {
|
||||||
pollingInterval: 20000,
|
pollingInterval: 60000,
|
||||||
|
skip: !userData.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -55,7 +67,26 @@ const useAppointments = () => {
|
|||||||
isLoading: isLoadingPatients,
|
isLoading: isLoadingPatients,
|
||||||
isError: isErrorPatients,
|
isError: isErrorPatients,
|
||||||
} = useGetAllPatientsQuery(undefined, {
|
} = useGetAllPatientsQuery(undefined, {
|
||||||
pollingInterval: 20000,
|
pollingInterval: 60000,
|
||||||
|
skip: !userData.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: upcomingAppointments = [],
|
||||||
|
isLoading: isLoadingUpcomingAppointments,
|
||||||
|
isError: isErrorUpcomingAppointments,
|
||||||
|
} = useGetUpcomingAppointmentsQuery(userData.id, {
|
||||||
|
pollingInterval: 60000,
|
||||||
|
skip: !userData.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: upcomingScheduledAppointments = [],
|
||||||
|
isLoading: isLoadingUpcomingScheduledAppointments,
|
||||||
|
isError: isErrorUpcomingScheduledAppointments,
|
||||||
|
} = useGetUpcomingScheduledAppointmentsQuery(userData.id, {
|
||||||
|
pollingInterval: 60000,
|
||||||
|
skip: !userData.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth);
|
const [localSiderWidth, setLocalSiderWidth] = useState(siderWidth);
|
||||||
@ -123,11 +154,10 @@ const useAppointments = () => {
|
|||||||
const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]);
|
const showSplitterPanel = useMemo(() => !collapsed && !screens.xs, [collapsed, screens]);
|
||||||
|
|
||||||
const upcomingEvents = useMemo(() =>
|
const upcomingEvents = useMemo(() =>
|
||||||
[...appointments, ...scheduledAppointments]
|
[...upcomingAppointments, ...upcomingScheduledAppointments]
|
||||||
.filter(app => dayjs(app.appointment_datetime || app.scheduled_datetime).isAfter(dayjs()))
|
.sort((a, b) => dayjs(a.appointment_datetime || a.scheduled_datetime).tz("Europe/Moscow") - dayjs(b.appointment_datetime || b.scheduled_datetime).tz("Europe/Moscow"))
|
||||||
.sort((a, b) => dayjs(a.appointment_datetime || a.scheduled_datetime) - dayjs(b.appointment_datetime || b.scheduled_datetime))
|
|
||||||
.slice(0, 5),
|
.slice(0, 5),
|
||||||
[appointments, scheduledAppointments]
|
[upcomingAppointments, upcomingScheduledAppointments]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -156,14 +186,36 @@ const useAppointments = () => {
|
|||||||
placement: 'topRight',
|
placement: 'topRight',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [isErrorAppointments, isErrorScheduledAppointments, isErrorPatients]);
|
if (isErrorUpcomingAppointments) {
|
||||||
|
notification.error({
|
||||||
|
message: 'Ошибка',
|
||||||
|
description: 'Ошибка загрузки предстоящих приемов.',
|
||||||
|
placement: 'topRight',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isErrorUpcomingScheduledAppointments) {
|
||||||
|
notification.error({
|
||||||
|
message: 'Ошибка',
|
||||||
|
description: 'Ошибка загрузки предстоящих запланированных приемов.',
|
||||||
|
placement: 'topRight',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
isErrorAppointments,
|
||||||
|
isErrorScheduledAppointments,
|
||||||
|
isErrorPatients,
|
||||||
|
isErrorUpcomingAppointments,
|
||||||
|
isErrorUpcomingScheduledAppointments
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
patients,
|
patients,
|
||||||
appointments,
|
appointments,
|
||||||
scheduledAppointments,
|
scheduledAppointments,
|
||||||
isLoading: isLoadingAppointments || isLoadingScheduledAppointments || isLoadingPatients,
|
isLoading: isLoadingAppointments || isLoadingScheduledAppointments || isLoadingPatients ||
|
||||||
isError: isErrorAppointments || isErrorScheduledAppointments || isErrorPatients,
|
isLoadingUpcomingAppointments || isLoadingUpcomingScheduledAppointments,
|
||||||
|
isError: isErrorAppointments || isErrorScheduledAppointments || isErrorPatients ||
|
||||||
|
isErrorUpcomingAppointments || isErrorUpcomingScheduledAppointments,
|
||||||
collapsed,
|
collapsed,
|
||||||
siderWidth: localSiderWidth,
|
siderWidth: localSiderWidth,
|
||||||
hovered,
|
hovered,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user