сделал конвертацию запланированного приема в обычный прием

This commit is contained in:
Андрей Дувакин 2025-06-01 20:43:06 +05:00
parent d101036445
commit 55369ac1a4
9 changed files with 102 additions and 70 deletions

View File

@ -11,7 +11,7 @@ from app.domain.entities.user import UserEntity
class ScheduledAppointmentEntity(BaseModel): class ScheduledAppointmentEntity(BaseModel):
id: Optional[int] = None id: Optional[int] = None
scheduled_datetime: datetime.datetime scheduled_datetime: datetime.datetime
is_canceled: bool is_canceled: Optional[bool] = False
patient_id: int patient_id: int
doctor_id: Optional[int] = None doctor_id: Optional[int] = None

View File

@ -131,7 +131,6 @@ const AppointmentsPage = () => {
</FloatButton.Group> </FloatButton.Group>
<AppointmentFormModal <AppointmentFormModal
visible={appointmentsPageUI.modalVisible}
onCancel={handleCancelModal} onCancel={handleCancelModal}
/> />

View File

@ -1,20 +1,13 @@
// useAppointmentCalendarUI.js
import {useDispatch, useSelector} from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import dayjs from "dayjs"; import dayjs from "dayjs";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone"; import timezone from "dayjs/plugin/timezone";
import {Form, Grid, notification} from "antd"; import {Grid} from "antd";
import { import {
closeModal,
openModal, setSelectedAppointment, openModal, setSelectedAppointment,
setSelectedAppointments, setSelectedAppointments,
setSelectedDate, setSelectedScheduledAppointment, setSelectedScheduledAppointment,
} from "../../../../../Redux/Slices/appointmentsSlice.js"; } from "../../../../../Redux/Slices/appointmentsSlice.js";
import {useCreateAppointmentMutation, useUpdateAppointmentMutation} from "../../../../../Api/appointmentsApi.js";
import {
useCreateScheduledAppointmentMutation,
useUpdateScheduledAppointmentMutation
} from "../../../../../Api/scheduledAppointmentsApi.js";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
@ -24,12 +17,6 @@ const {useBreakpoint} = Grid;
const useAppointmentCalendarUI = (appointments, scheduledAppointments) => { const useAppointmentCalendarUI = (appointments, scheduledAppointments) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const {
modalVisible,
selectedAppointments,
selectedAppointment,
selectedScheduledAppointment,
} = useSelector(state => state.appointmentsUI);
const selectedDate = dayjs.tz(useSelector(state => state.appointmentsUI.selectedDate), 'Europe/Moscow'); const selectedDate = dayjs.tz(useSelector(state => state.appointmentsUI.selectedDate), 'Europe/Moscow');
const screens = useBreakpoint(); const screens = useBreakpoint();
@ -39,7 +26,7 @@ const useAppointmentCalendarUI = (appointments, scheduledAppointments) => {
const onSelect = (date) => { const onSelect = (date) => {
const selectedDateStr = date.format('YYYY-MM-DD'); const selectedDateStr = date.format('YYYY-MM-DD');
dispatch(setSelectedDate(selectedDateStr)); // dispatch(setSelectedDate(selectedDateStr));
const appointmentsForDate = appointments.filter(app => const appointmentsForDate = appointments.filter(app =>
dayjs(app.appointment_datetime).format('YYYY-MM-DD') === selectedDateStr dayjs(app.appointment_datetime).format('YYYY-MM-DD') === selectedDateStr
@ -62,10 +49,9 @@ const useAppointmentCalendarUI = (appointments, scheduledAppointments) => {
}; };
const getAppointmentsByListAndDate = (list, value, isScheduled = false) => { const getAppointmentsByListAndDate = (list, value, isScheduled = false) => {
const date = value.tz('Europe/Moscow').format('YYYY-MM-DD'); const date = value.format('YYYY-MM-DD');
return list.filter(app => return list.filter(app =>
dayjs(isScheduled ? app.scheduled_datetime : app.appointment_datetime) dayjs(isScheduled ? app.scheduled_datetime : app.appointment_datetime)
.tz('Europe/Moscow')
.format('YYYY-MM-DD') === date .format('YYYY-MM-DD') === date
); );
}; };

View File

@ -28,6 +28,7 @@ const AppointmentFormModal = ({onCancel}) => {
onCancel, onCancel,
appointmentFormModalData.createAppointment, appointmentFormModalData.createAppointment,
appointmentFormModalData.patients, appointmentFormModalData.patients,
appointmentFormModalData.cancelAppointment,
); );
const editor = useRef(null); const editor = useRef(null);

View File

@ -1,6 +1,7 @@
import {useGetPatientsQuery} from "../../../../../Api/patientsApi.js"; import {useGetPatientsQuery} from "../../../../../Api/patientsApi.js";
import {useGetAppointmentTypesQuery} from "../../../../../Api/appointmentTypesApi.js"; import {useGetAppointmentTypesQuery} from "../../../../../Api/appointmentTypesApi.js";
import {useCreateAppointmentMutation, useUpdateAppointmentMutation} from "../../../../../Api/appointmentsApi.js"; import {useCreateAppointmentMutation, useUpdateAppointmentMutation} from "../../../../../Api/appointmentsApi.js";
import {useCancelScheduledAppointmentMutation} from "../../../../../Api/scheduledAppointmentsApi.js";
const useAppointmentFormModal = () => { const useAppointmentFormModal = () => {
const { const {
@ -19,11 +20,13 @@ const useAppointmentFormModal = () => {
}); });
const [createAppointment, {isLoading: isCreating, isError: isErrorCreating}] = useCreateAppointmentMutation(); const [createAppointment, {isLoading: isCreating, isError: isErrorCreating}] = useCreateAppointmentMutation();
const [cancelAppointment] = useCancelScheduledAppointmentMutation();
return { return {
patients, patients,
appointmentTypes, appointmentTypes,
createAppointment, createAppointment,
cancelAppointment,
isLoading: isLoadingPatients || isLoadingAppointmentTypes || isCreating, isLoading: isLoadingPatients || isLoadingAppointmentTypes || isCreating,
isError: isErrorPatients || isErrorAppointmentTypes || isErrorCreating, isError: isErrorPatients || isErrorAppointmentTypes || isErrorCreating,
}; };

View File

@ -1,6 +1,6 @@
import {Form, notification} from "antd"; import {Form, notification} from "antd";
import {useDispatch, useSelector} from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import {closeModal} from "../../../../../Redux/Slices/appointmentsSlice.js"; import {closeModal, setSelectedScheduledAppointment} from "../../../../../Redux/Slices/appointmentsSlice.js";
import {useEffect, useMemo, useState} from "react"; import {useEffect, useMemo, useState} from "react";
import dayjs from "dayjs"; import dayjs from "dayjs";
import {useGetAppointmentsQuery} from "../../../../../Api/appointmentsApi.js"; import {useGetAppointmentsQuery} from "../../../../../Api/appointmentsApi.js";
@ -8,9 +8,9 @@ import {Grid} from "antd";
const {useBreakpoint} = Grid; const {useBreakpoint} = Grid;
const useAppointmentFormModalUI = (onCancel, createAppointment, patients) => { const useAppointmentFormModalUI = (onCancel, createAppointment, patients, cancelAppointment) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const {modalVisible} = useSelector(state => state.appointmentsUI); const {modalVisible, scheduledData} = useSelector(state => state.appointmentsUI);
const [form] = Form.useForm(); const [form] = Form.useForm();
const screens = useBreakpoint(); const screens = useBreakpoint();
@ -53,11 +53,24 @@ const useAppointmentFormModalUI = (onCancel, createAppointment, patients) => {
setSearchPatientString(""); setSearchPatientString("");
setFormValues({}); setFormValues({});
form.setFieldsValue({ if (scheduledData) {
appointment_datetime: dayjs(new Date()), const patient = patients.find(p => p.id === scheduledData.patient_id);
}) if (patient) {
setSelectedPatient(patient);
setCurrentStep(1); // Skip to appointment details step
form.setFieldsValue({
patient_id: scheduledData.patient_id,
type_id: scheduledData.type_id,
appointment_datetime: dayjs(scheduledData.appointment_datetime),
});
}
} else {
form.setFieldsValue({
appointment_datetime: dayjs(new Date()),
});
}
} }
}, [modalVisible, form]); }, [modalVisible, form, scheduledData, patients]);
const handleResultsChange = (newContent) => { const handleResultsChange = (newContent) => {
setResults(newContent); setResults(newContent);
@ -144,8 +157,13 @@ const useAppointmentFormModalUI = (onCancel, createAppointment, patients) => {
results: results, results: results,
}; };
await createAppointment(data).unwrap(); await createAppointment(data).unwrap();
if (scheduledData) {
await cancelScheduledAppointment(scheduledData.id);
dispatch(setSelectedScheduledAppointment(null));
}
notification.success({ notification.success({
message: 'Прием создан', message: 'Прием создан',
description: 'Прием успешно создан.', description: 'Прием успешно создан.',
@ -166,6 +184,18 @@ const useAppointmentFormModalUI = (onCancel, createAppointment, patients) => {
} }
}; };
const cancelScheduledAppointment = async (selectedScheduledAppointmentId) => {
try {
await cancelAppointment(selectedScheduledAppointmentId);
} catch (error) {
notification.error({
message: 'Ошибка',
description: error.data?.message || 'Не удалось отменить прием.',
placement: 'topRight',
})
}
};
const handleCancel = () => { const handleCancel = () => {
form.resetFields(); form.resetFields();
setSelectedPatient(null); setSelectedPatient(null);

View File

@ -25,14 +25,16 @@ const useScheduledAppointmentFormModalUI = (patients, createScheduledAppointment
type_id: selectedAppointmentType type_id: selectedAppointmentType
}; };
console.log(data)
await createScheduledAppointment(data).unwrap(); await createScheduledAppointment(data).unwrap();
notification.success({ notification.success({
message: 'Прием создан', message: 'Прием создан',
placement: 'topRight', placement: 'topRight',
description: 'Прием успешно запланирован.', description: 'Прием успешно запланирован.',
}) });
setSelectedPatient(null);
setSelectedDateTime(dayjs(new Date()).add(1, 'day'));
setSelectedAppointmentType(null);
dispatch(closeScheduledModal()); dispatch(closeScheduledModal());
} catch (error) { } catch (error) {

View File

@ -2,8 +2,11 @@ import {Button, Modal, Popconfirm, Row, Typography} from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import useScheduledAppointmentsViewModal from "./useScheduledAppointmentsViewModal.js"; import useScheduledAppointmentsViewModal from "./useScheduledAppointmentsViewModal.js";
import useScheduledAppointmentsViewModalUI from "./useScheduledAppointmentsViewModalUI.js"; import useScheduledAppointmentsViewModalUI from "./useScheduledAppointmentsViewModalUI.js";
import { useDispatch } from "react-redux";
import {openModalWithScheduledData} from "../../../../../Redux/Slices/appointmentsSlice.js";
const ScheduledAppointmentsViewModal = () => { const ScheduledAppointmentsViewModal = () => {
const dispatch = useDispatch();
const scheduledAppointmentsViewModalData = useScheduledAppointmentsViewModal(); const scheduledAppointmentsViewModalData = useScheduledAppointmentsViewModal();
const scheduledAppointmentsViewModalUI = useScheduledAppointmentsViewModalUI(scheduledAppointmentsViewModalData.cancelAppointment); const scheduledAppointmentsViewModalUI = useScheduledAppointmentsViewModalUI(scheduledAppointmentsViewModalData.cancelAppointment);
@ -11,6 +14,15 @@ const ScheduledAppointmentsViewModal = () => {
return null; return null;
} }
const handleConvertToAppointment = () => {
dispatch(openModalWithScheduledData({
id: scheduledAppointmentsViewModalUI.selectedScheduledAppointment.id,
patient_id: scheduledAppointmentsViewModalUI.selectedScheduledAppointment.patient?.id,
type_id: scheduledAppointmentsViewModalUI.selectedScheduledAppointment.type?.id,
appointment_datetime: scheduledAppointmentsViewModalUI.selectedScheduledAppointment.scheduled_datetime,
}));
};
return ( return (
<Modal <Modal
title="Просмотр запланированного приема" title="Просмотр запланированного приема"
@ -51,6 +63,9 @@ const ScheduledAppointmentsViewModal = () => {
onClick={scheduledAppointmentsViewModalUI.onCancel}> onClick={scheduledAppointmentsViewModalUI.onCancel}>
Закрыть Закрыть
</Button> </Button>
<Button type="primary" onClick={handleConvertToAppointment}>
Конвертировать в прием
</Button>
<Popconfirm <Popconfirm
title="Вы уверены, что хотите отменить прием?" title="Вы уверены, что хотите отменить прием?"
onConfirm={scheduledAppointmentsViewModalUI.cancelScheduledAppointment} onConfirm={scheduledAppointmentsViewModalUI.cancelScheduledAppointment}
@ -62,7 +77,6 @@ const ScheduledAppointmentsViewModal = () => {
</Button> </Button>
</Popconfirm> </Popconfirm>
</Row> </Row>
</Modal> </Modal>
); );
}; };

View File

@ -1,72 +1,69 @@
import { createSlice } from "@reduxjs/toolkit"; import { createSlice } from '@reduxjs/toolkit';
const initialState = { const initialState = {
collapsed: true,
siderWidth: 250,
hovered: false,
modalVisible: false, modalVisible: false,
scheduledModalVisible: false, collapsed: true,
siderWidth: 300,
hovered: false,
selectedAppointment: null, selectedAppointment: null,
scheduledAppointments: [],
selectedScheduledAppointment: null, selectedScheduledAppointment: null,
scheduledModalVisible: false,
scheduledData: null,
selectedAppointments: [], // Новое поле для хранения массива выбранных приемов
}; };
const appointmentsSlice = createSlice({ const appointmentsSlice = createSlice({
name: 'appointmentsUI', name: 'appointmentsUI',
initialState, initialState,
reducers: { reducers: {
toggleSider: (state) => { openModal(state) {
state.collapsed = !state.collapsed;
},
setSiderWidth: (state, action) => {
state.siderWidth = action.payload;
},
setHovered: (state, action) => {
state.hovered = action.payload;
},
setSelectedDate: (state, action) => {
state.selectedDate = action.payload;
},
openModal: (state) => {
state.modalVisible = true; state.modalVisible = true;
}, },
closeModal: (state) => { closeModal(state) {
state.modalVisible = false; state.modalVisible = false;
}, },
openScheduledModal: (state) => { toggleSider(state) {
state.scheduledModalVisible = true; state.collapsed = !state.collapsed;
}, },
closeScheduledModal: (state) => { setSiderWidth(state, action) {
state.scheduledModalVisible = false; state.siderWidth = action.payload;
}, },
setSelectedAppointments: (state, action) => { setHovered(state, action) {
state.selectedAppointments = action.payload; state.hovered = action.payload;
}, },
setSelectedAppointment: (state, action) => { setSelectedAppointment(state, action) {
state.selectedAppointment = action.payload; state.selectedAppointment = action.payload;
}, },
setScheduledAppointments: (state, action) => { setSelectedScheduledAppointment(state, action) {
state.scheduledAppointments = action.payload;
},
setSelectedScheduledAppointment: (state, action) => {
state.selectedScheduledAppointment = action.payload; state.selectedScheduledAppointment = action.payload;
}, },
} openScheduledModal(state) {
state.scheduledModalVisible = true;
},
closeScheduledModal(state) {
state.scheduledModalVisible = false;
},
openModalWithScheduledData(state, action) {
state.modalVisible = true;
state.scheduledData = action.payload;
},
setSelectedAppointments(state, action) {
state.selectedAppointments = action.payload;
},
},
}); });
export const { export const {
toggleSider,
setSiderWidth,
setHovered,
setSelectedDate,
openModal, openModal,
closeModal, closeModal,
setSelectedAppointments, toggleSider,
setHovered,
setSelectedAppointment, setSelectedAppointment,
setSelectedScheduledAppointment, setSelectedScheduledAppointment,
setScheduledAppointments,
openScheduledModal, openScheduledModal,
closeScheduledModal, closeScheduledModal,
openModalWithScheduledData,
setSelectedAppointments,
} = appointmentsSlice.actions; } = appointmentsSlice.actions;
export default appointmentsSlice.reducer; export default appointmentsSlice.reducer;