refactor: AppointmentView: Переименован hook и убран console.log

This commit is contained in:
Андрей Дувакин 2025-06-04 19:24:09 +05:00
parent 4dca2314cc
commit a416b6cc95
3 changed files with 40 additions and 32 deletions

View File

@ -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 appointmentFilesApi = createApi({ export const appointmentFilesApi = createApi({
reducerPath: 'appointmentFilesApi', reducerPath: 'appointmentFilesApi',
@ -8,7 +8,6 @@ export const appointmentFilesApi = createApi({
endpoints: (builder) => ({ endpoints: (builder) => ({
getAppointmentFiles: builder.query({ getAppointmentFiles: builder.query({
query: (appointmentId) => { query: (appointmentId) => {
console.log(`Fetching files for appointment ID: ${appointmentId}`);
return `/appointment_files/${appointmentId}/`; return `/appointment_files/${appointmentId}/`;
}, },
providesTags: ['AppointmentFile'], providesTags: ['AppointmentFile'],
@ -22,7 +21,7 @@ export const appointmentFilesApi = createApi({
invalidatesTags: ['AppointmentFile'], invalidatesTags: ['AppointmentFile'],
}), }),
uploadAppointmentFile: builder.mutation({ uploadAppointmentFile: builder.mutation({
query: ({ appointmentId, file }) => { query: ({appointmentId, file}) => {
if (!(file instanceof File)) { if (!(file instanceof File)) {
throw new Error('Invalid file object'); throw new Error('Invalid file object');
} }

View File

@ -1,5 +1,5 @@
import { Button, Modal, Row, Typography, Spin } from "antd"; import {Button, Modal, Row, Typography, Spin, Splitter, Divider} from "antd";
import useAppointmentViewUI from "./useAppointmentViewUI.js"; import useAppointmentView from "./useAppointmentView.js";
const AppointmentViewModal = () => { const AppointmentViewModal = () => {
const { const {
@ -20,7 +20,7 @@ const AppointmentViewModal = () => {
isFilesLoading, isFilesLoading,
downloadingFiles, downloadingFiles,
downloadFile, downloadFile,
} = useAppointmentViewUI(); } = useAppointmentView();
if (!selectedAppointment) { if (!selectedAppointment) {
return null; return null;
@ -67,26 +67,27 @@ const AppointmentViewModal = () => {
<b>{labels.results}</b> <b>{labels.results}</b>
</p> </p>
<div <div
dangerouslySetInnerHTML={{ __html: getResults(selectedAppointment.results) }} dangerouslySetInnerHTML={{__html: getResults(selectedAppointment.results)}}
/> />
<p> <p>
<b>{labels.files}</b> <b>{labels.files}</b>
</p> </p>
{isFilesLoading ? ( {isFilesLoading ? (
<Spin /> <Spin/>
) : files.length > 0 ? ( ) : files.length > 0 ? (
files.map((file) => ( files.map((file) => (
<div key={file.id} style={{ marginBottom: 8 }}> <Row key={file.id} align="middle" justify="space-between">
<span>{file.file_title || labels.notSpecified}</span> <span>{file.file_title || labels.notSpecified}</span>
<Button <Button
style={{ marginLeft: 8 }}
onClick={() => downloadFile(file.id, file.file_title)} onClick={() => downloadFile(file.id, file.file_title)}
loading={downloadingFiles[file.id] || false} loading={downloadingFiles[file.id] || false}
disabled={downloadingFiles[file.id] || false} disabled={downloadingFiles[file.id] || false}
type={"dashed"}
> >
{downloadingFiles[file.id] ? labels.downloading : labels.download} {downloadingFiles[file.id] ? labels.downloading : labels.download}
</Button> </Button>
</div> <Divider/>
</Row>
)) ))
) : ( ) : (
<p>{labels.noFiles}</p> <p>{labels.noFiles}</p>

View File

@ -1,25 +1,26 @@
import { useDispatch, useSelector } from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import { setSelectedAppointment } from "../../../Redux/Slices/appointmentsSlice.js"; import {setSelectedAppointment} from "../../../Redux/Slices/appointmentsSlice.js";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useState } from "react"; import {useState} from "react";
import {useGetAppointmentFilesQuery} from "../../../Api/appointmentFilesApi.js"; import {useGetAppointmentFilesQuery} from "../../../Api/appointmentFilesApi.js";
import {baseQueryWithAuth} from "../../../Api/baseQuery.js"; import {baseQueryWithAuth} from "../../../Api/baseQuery.js";
import {notification} from "antd";
const useAppointmentViewUI = () => { const useAppointmentView = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { selectedAppointment } = useSelector((state) => state.appointmentsUI); const {selectedAppointment} = useSelector((state) => state.appointmentsUI);
const { data: files = [], isLoading: isFilesLoading } = useGetAppointmentFilesQuery( const {data: files = [], isLoading: isFilesLoading} = useGetAppointmentFilesQuery(
selectedAppointment?.id, selectedAppointment?.id,
{ skip: !selectedAppointment?.id } {skip: !selectedAppointment?.id}
); );
const [downloadingFiles, setDownloadingFiles] = useState({}); const [downloadingFiles, setDownloadingFiles] = useState({});
const modalWidth = 700; const modalWidth = 700;
const blockStyle = { marginBottom: 16 }; const blockStyle = {marginBottom: 16};
const footerRowStyle = { marginTop: 16 }; const footerRowStyle = {marginTop: 16};
const footerButtonStyle = { marginRight: 8 }; const footerButtonStyle = {marginRight: 8};
const labels = { const labels = {
title: "Просмотр приема", title: "Просмотр приема",
@ -72,19 +73,17 @@ const useAppointmentViewUI = () => {
const downloadFile = async (fileId, fileName) => { const downloadFile = async (fileId, fileName) => {
try { try {
setDownloadingFiles((prev) => ({ ...prev, [fileId]: true })); setDownloadingFiles((prev) => ({...prev, [fileId]: true}));
// Выполняем запрос с использованием fetch, применяя baseQueryWithAuth для аутентификации const {url, ...options} = await baseQueryWithAuth(
const { url, ...options } = await baseQueryWithAuth(
{ {
url: `/appointment_files/${fileId}/file/`, url: `/appointment_files/${fileId}/file/`,
method: 'GET', method: 'GET',
credentials: 'include', credentials: 'include',
}, },
{ getState: () => ({}) }, {},
{} {}
); );
// Поскольку baseQueryWithAuth может вернуть объект с полной URL, используем его
const response = await fetch(url, { const response = await fetch(url, {
...options, ...options,
method: 'GET', method: 'GET',
@ -92,7 +91,11 @@ const useAppointmentViewUI = () => {
}); });
if (!response.ok) { if (!response.ok) {
throw new Error(`Ошибка HTTP: ${response.status} ${response.statusText}`); notification.error({
message: "Ошибка при скачивании файла",
description: "Не удалось загрузить файл.",
placement: "topRight",
});
} }
const blob = await response.blob(); const blob = await response.blob();
@ -104,11 +107,16 @@ const useAppointmentViewUI = () => {
link.click(); link.click();
link.remove(); link.remove();
window.URL.revokeObjectURL(downloadUrl); window.URL.revokeObjectURL(downloadUrl);
} catch (error) { } catch (error) {
console.error("Ошибка при скачивании файла:", error); console.error("Error downloading file:", error);
// Можно добавить уведомление, например, с antd message notification.error({
message: "Ошибка при скачивании файлов",
description: "Не удалось загрузить файл.",
placement: "topRight",
});
} finally { } finally {
setDownloadingFiles((prev) => ({ ...prev, [fileId]: false })); setDownloadingFiles((prev) => ({...prev, [fileId]: false}));
} }
}; };
@ -133,4 +141,4 @@ const useAppointmentViewUI = () => {
}; };
}; };
export default useAppointmentViewUI; export default useAppointmentView;