Перемещены компоненты и хуки для AppointmentViewModal. Обновлены импорты в HomePage и AppointmentsPage. Добавлено вывод на печать результатов приема
238 lines
8.7 KiB
JavaScript
238 lines
8.7 KiB
JavaScript
import { useDispatch, useSelector } from "react-redux";
|
||
import { setSelectedAppointment } from "../../../Redux/Slices/appointmentsSlice.js";
|
||
import dayjs from "dayjs";
|
||
import { useState } from "react";
|
||
import { useGetAppointmentFilesQuery, useDeleteAppointmentFileMutation } from "../../../Api/appointmentFilesApi.js";
|
||
import { baseQueryWithAuth } from "../../../Api/baseQuery.js";
|
||
import { notification } from "antd";
|
||
|
||
const useAppointmentView = () => {
|
||
const dispatch = useDispatch();
|
||
const { selectedAppointment } = useSelector((state) => state.appointmentsUI);
|
||
|
||
const { data: files = [], isLoading: isFilesLoading } = useGetAppointmentFilesQuery(
|
||
selectedAppointment?.id,
|
||
{ skip: !selectedAppointment?.id }
|
||
);
|
||
|
||
const [deleteAppointmentFile, { isLoading: isDeletingFile }] = useDeleteAppointmentFileMutation();
|
||
|
||
const [downloadingFiles, setDownloadingFiles] = useState({});
|
||
const [deletingFiles, setDeletingFiles] = useState({});
|
||
|
||
const modalWidth = 700;
|
||
const blockStyle = { marginBottom: 16 };
|
||
const footerRowStyle = { marginTop: 16 };
|
||
const footerButtonStyle = { marginRight: 8 };
|
||
|
||
const labels = {
|
||
title: "Просмотр приема",
|
||
patient: "Пациент:",
|
||
birthday: "Дата рождения:",
|
||
email: "Email:",
|
||
phone: "Телефон:",
|
||
type: "Тип приема:",
|
||
appointmentTime: "Время приема:",
|
||
daysUntilNext: "Дней до следующего приема:",
|
||
results: "Результаты приема:",
|
||
closeButton: "Закрыть",
|
||
notSpecified: "Не указан",
|
||
resultsNotSpecified: "Не указаны",
|
||
files: "Файлы:",
|
||
noFiles: "Файлы отсутствуют",
|
||
download: "Скачать",
|
||
downloading: "Загрузка...",
|
||
delete: "Удалить",
|
||
deleting: "Удаление...",
|
||
confirmDelete: "Вы уверены, что хотите удалить файл?",
|
||
printResults: "Печать результатов",
|
||
};
|
||
|
||
const visible = !!selectedAppointment;
|
||
|
||
const getDateString = (date) => {
|
||
return date ? new Date(date).toLocaleDateString("ru-RU") : labels.notSpecified;
|
||
};
|
||
|
||
const getAppointmentTime = (datetime) => {
|
||
return datetime
|
||
? dayjs(datetime).format("DD.MM.YYYY HH:mm")
|
||
: labels.notSpecified;
|
||
};
|
||
|
||
const getPatientName = (patient) => {
|
||
return patient
|
||
? `${patient.last_name} ${patient.first_name}`
|
||
: labels.notSpecified;
|
||
};
|
||
|
||
const getPatientField = (field) => {
|
||
return field || labels.notSpecified;
|
||
};
|
||
|
||
const getResults = (results) => {
|
||
return results || labels.resultsNotSpecified;
|
||
};
|
||
|
||
const onCancel = () => {
|
||
dispatch(setSelectedAppointment(null));
|
||
};
|
||
|
||
const downloadFile = async (fileId, fileName) => {
|
||
try {
|
||
setDownloadingFiles((prev) => ({ ...prev, [fileId]: true }));
|
||
const { url, ...options } = await baseQueryWithAuth(
|
||
{
|
||
url: `/appointment_files/${fileId}/file/`,
|
||
method: 'GET',
|
||
credentials: 'include',
|
||
},
|
||
{},
|
||
{}
|
||
);
|
||
|
||
const response = await fetch(url, {
|
||
...options,
|
||
method: 'GET',
|
||
credentials: 'include',
|
||
});
|
||
|
||
if (!response.ok) {
|
||
notification.error({
|
||
message: "Ошибка при скачивании файла",
|
||
description: "Не удалось загрузить файл.",
|
||
placement: "topRight",
|
||
});
|
||
}
|
||
|
||
const blob = await response.blob();
|
||
const downloadUrl = window.URL.createObjectURL(blob);
|
||
const link = document.createElement("a");
|
||
link.href = downloadUrl;
|
||
link.setAttribute("download", fileName || "file");
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
link.remove();
|
||
window.URL.revokeObjectURL(downloadUrl);
|
||
} catch (error) {
|
||
console.error("Error downloading file:", error);
|
||
notification.error({
|
||
message: "Ошибка при скачивании файлов",
|
||
description: "Не удалось загрузить файл.",
|
||
placement: "topRight",
|
||
});
|
||
} finally {
|
||
setDownloadingFiles((prev) => ({ ...prev, [fileId]: false }));
|
||
}
|
||
};
|
||
|
||
const deleteFile = async (fileId, fileName) => {
|
||
try {
|
||
setDeletingFiles((prev) => ({ ...prev, [fileId]: true }));
|
||
await deleteAppointmentFile(fileId).unwrap();
|
||
notification.success({
|
||
message: "Файл удален",
|
||
description: `Файл ${fileName || "неизвестный"} успешно удален.`,
|
||
placement: "topRight",
|
||
});
|
||
} catch (error) {
|
||
console.error("Error deleting file:", error);
|
||
notification.error({
|
||
message: "Ошибка при удалении файла",
|
||
description: `Не удалось удалить файл ${fileName || "неизвестный"}: ${error.data?.detail || error.message}`,
|
||
placement: "topRight",
|
||
});
|
||
} finally {
|
||
setDeletingFiles((prev) => ({ ...prev, [fileId]: false }));
|
||
}
|
||
};
|
||
|
||
const printResults = () => {
|
||
if (!selectedAppointment?.results || selectedAppointment.results === labels.resultsNotSpecified) {
|
||
notification.error({
|
||
message: "Ошибка печати",
|
||
description: "Результаты приема отсутствуют.",
|
||
placement: "topRight",
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const results = getResults(selectedAppointment.results);
|
||
const patientName = getPatientName(selectedAppointment.patient);
|
||
const appointmentTime = getAppointmentTime(selectedAppointment.appointment_datetime);
|
||
|
||
const printWindow = window.open('', '_blank', 'width=800,height=600');
|
||
if (!printWindow) {
|
||
notification.error({
|
||
message: "Ошибка печати",
|
||
description: "Не удалось открыть окно для печати. Проверьте настройки блокировки всплывающих окон.",
|
||
placement: "topRight",
|
||
});
|
||
return;
|
||
}
|
||
|
||
printWindow.document.write(`
|
||
<html>
|
||
<head>
|
||
<title>Результаты приема - ${patientName}</title>
|
||
<style>
|
||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||
h1 { font-size: 24px; }
|
||
h2 { font-size: 18px; margin-bottom: 10px; }
|
||
.results { font-size: 16px; line-height: 1.5; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>Результаты приема</h1>
|
||
<h2>Пациент: ${patientName}</h2>
|
||
<h2>Дата и время приема: ${appointmentTime}</h2>
|
||
<div class="results">${results}</div>
|
||
</body>
|
||
</html>
|
||
`);
|
||
printWindow.document.close();
|
||
|
||
printWindow.onload = () => {
|
||
printWindow.focus();
|
||
printWindow.print();
|
||
setTimeout(() => {
|
||
printWindow.close();
|
||
}, 500);
|
||
};
|
||
} catch (error) {
|
||
console.error("Error printing results:", error);
|
||
notification.error({
|
||
message: "Ошибка печати",
|
||
description: "Не удалось выполнить печать. Попробуйте снова.",
|
||
placement: "topRight",
|
||
});
|
||
}
|
||
};
|
||
|
||
return {
|
||
modalWidth,
|
||
blockStyle,
|
||
footerRowStyle,
|
||
footerButtonStyle,
|
||
labels,
|
||
selectedAppointment,
|
||
visible,
|
||
getDateString,
|
||
getAppointmentTime,
|
||
getPatientName,
|
||
getPatientField,
|
||
getResults,
|
||
onCancel,
|
||
files,
|
||
isFilesLoading,
|
||
downloadingFiles,
|
||
downloadFile,
|
||
deletingFiles,
|
||
deleteFile,
|
||
isDeletingFile,
|
||
printResults,
|
||
};
|
||
};
|
||
|
||
export default useAppointmentView; |