From 64b0a19408e894ec74218e48614ccb61b353a30e Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 4 Jun 2025 13:31:54 +0500 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=A4=D0=BE=D1=80=D0=BC=D0=B0=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D0=B8=D1=81=D0=B8=20-=20=D0=97=D0=B0=D0=B3=D1=80?= =?UTF-8?q?=D1=83=D0=B7=D0=BA=D0=B0=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/main.py | 11 +++-- web-app/src/Api/appointmentFilesApi.js | 47 ++----------------- web-app/src/Api/baseQuery.js | 20 ++++---- .../AppointmentFormModal.jsx | 22 --------- .../useAppointmentFormModalUI.js | 41 ++++------------ 5 files changed, 31 insertions(+), 110 deletions(-) diff --git a/api/app/main.py b/api/app/main.py index df4b959..1c49422 100644 --- a/api/app/main.py +++ b/api/app/main.py @@ -23,14 +23,16 @@ def start_app(): api_app.add_middleware( CORSMiddleware, - allow_origins=['http://localhost:5173'], + allow_origins=['http://localhost:5173', 'http://localhost:5173'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'], ) - api_app.include_router(appointment_files_router, prefix=f'{settings.APP_PREFIX}/appointment_files', tags=['appointment_files']) - api_app.include_router(appointments_types_router, prefix=f'{settings.APP_PREFIX}/appointment_types', tags=['appointment_types']) + api_app.include_router(appointment_files_router, prefix=f'{settings.APP_PREFIX}/appointment_files', + tags=['appointment_files']) + api_app.include_router(appointments_types_router, prefix=f'{settings.APP_PREFIX}/appointment_types', + tags=['appointment_types']) api_app.include_router(appointment_router, prefix=f'{settings.APP_PREFIX}/appointments', tags=['appointments']) api_app.include_router(auth_router, prefix=settings.APP_PREFIX, tags=['auth']) api_app.include_router(lens_issues_router, prefix=f'{settings.APP_PREFIX}/lens_issues', tags=['lens_issue']) @@ -39,7 +41,8 @@ def start_app(): api_app.include_router(patients_router, prefix=f'{settings.APP_PREFIX}/patients', tags=['patients']) api_app.include_router(register_router, prefix=f'{settings.APP_PREFIX}/register', tags=['register']) api_app.include_router(roles_router, prefix=f'{settings.APP_PREFIX}/roles', tags=['roles']) - api_app.include_router(scheduled_appointments_router, prefix=f'{settings.APP_PREFIX}/scheduled_appointments', tags=['scheduled_appointments']) + api_app.include_router(scheduled_appointments_router, prefix=f'{settings.APP_PREFIX}/scheduled_appointments', + tags=['scheduled_appointments']) api_app.include_router(set_content_router, prefix=f'{settings.APP_PREFIX}/set_content', tags=['set_content']) api_app.include_router(sets_router, prefix=f'{settings.APP_PREFIX}/sets', tags=['sets']) api_app.include_router(users_router, prefix=f'{settings.APP_PREFIX}/users', tags=['users']) diff --git a/web-app/src/Api/appointmentFilesApi.js b/web-app/src/Api/appointmentFilesApi.js index 9c8d859..cfe7274 100644 --- a/web-app/src/Api/appointmentFilesApi.js +++ b/web-app/src/Api/appointmentFilesApi.js @@ -1,65 +1,28 @@ -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 appointmentFilesApi = createApi({ reducerPath: 'appointmentFilesApi', baseQuery: baseQueryWithAuth, tagTypes: ['AppointmentFile'], endpoints: (builder) => ({ - getAppointmentFiles: builder.query({ - query: (appointmentId) => { - console.log(`Fetching files for appointment ID: ${appointmentId}`); - return `/appointment_files/${appointmentId}/`; - }, - providesTags: ['AppointmentFile'], - refetchOnMountOrArgChange: 5, - }), - downloadAppointmentFile: builder.query({ - query: (fileId) => ({ - url: `/appointment_files/${fileId}/file/`, - responseHandler: async (response) => { - const blob = await response.blob(); - const contentDisposition = response.headers.get('content-disposition'); - const filename = contentDisposition - ? contentDisposition.match(/filename="(.+)"/)?.[1] || `file_${fileId}` - : `file_${fileId}`; - return {blob, filename}; - }, - cache: 'no-cache', - }), - }), uploadAppointmentFile: builder.mutation({ - query: ({appointmentId, file}) => { - console.log(`File details:`, { - name: file.name, - size: file.size, - type: file.type, - isFile: file instanceof File, - }); + query: ({ appointmentId, file }) => { if (!(file instanceof File)) { - console.error('Expected a File object, received:', file); throw new Error('Invalid file object'); } const formData = new FormData(); formData.append('file', file); - for (let [key, value] of formData.entries()) { - console.log(`FormData entry: ${key}=${value.name || value}`); - } return { url: `/appointment_files/${appointmentId}/upload/`, method: 'POST', + credentials: 'include', + formData: true, body: formData, }; }, invalidatesTags: ['AppointmentFile'], }), - deleteAppointmentFile: builder.mutation({ - query: (fileId) => ({ - url: `/appointment_files/${fileId}/`, - method: 'DELETE', - }), - invalidatesTags: ['AppointmentFile'], - }), }), }); diff --git a/web-app/src/Api/baseQuery.js b/web-app/src/Api/baseQuery.js index 2dcf95e..360fcbf 100644 --- a/web-app/src/Api/baseQuery.js +++ b/web-app/src/Api/baseQuery.js @@ -1,24 +1,24 @@ -import {fetchBaseQuery} from '@reduxjs/toolkit/query/react'; -import {logout} from '../Redux/Slices/authSlice.js'; +import { fetchBaseQuery } from '@reduxjs/toolkit/query/react'; +import { logout } from '../Redux/Slices/authSlice.js'; import CONFIG from "../Core/сonfig.js"; export const baseQuery = fetchBaseQuery({ baseUrl: CONFIG.BASE_URL, - prepareHeaders: (headers, {getState}) => { + prepareHeaders: (headers, { getState, endpoint }) => { const token = localStorage.getItem('access_token'); if (token) { headers.set('Authorization', `Bearer ${token}`); } - const body = getState()?.api?.mutations?.[Object.keys(getState()?.api?.mutations || {})[0]]?.body; - if (!(body instanceof FormData)) { - headers.set('Content-Type', 'application/json'); - } else { - console.log('FormData request headers:', headers); - for (let [key, value] of body.entries()) { - console.log(`FormData entry: ${key}=${value.name || value}`); + if (endpoint === 'uploadAppointmentFile') { + const mutation = getState()?.api?.mutations?.[Object.keys(getState()?.api?.mutations || {})[0]]; + if (mutation?.body instanceof FormData) { + headers.delete('Content-Type'); } + } else { + headers.set('Content-Type', 'application/json'); } + return headers; }, }); diff --git a/web-app/src/Components/Dummies/AppointmentFormModal/AppointmentFormModal.jsx b/web-app/src/Components/Dummies/AppointmentFormModal/AppointmentFormModal.jsx index d13ec6d..22fc04f 100644 --- a/web-app/src/Components/Dummies/AppointmentFormModal/AppointmentFormModal.jsx +++ b/web-app/src/Components/Dummies/AppointmentFormModal/AppointmentFormModal.jsx @@ -210,28 +210,6 @@ const AppointmentFormModal = () => { > - {appointmentFormModalUI.draftFiles.length > 0 && ( - ( - appointmentFormModalUI.handleRemoveFile(file)} - > - Удалить - - ]} - > - {file.name} ({(file.size / 1024 / 1024).toFixed(2)} MB) - - )} - /> - )} diff --git a/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js b/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js index 6cb6f6e..51f75bb 100644 --- a/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js +++ b/web-app/src/Components/Dummies/AppointmentFormModal/useAppointmentFormModalUI.js @@ -7,8 +7,6 @@ import {useGetAppointmentsQuery} from "../../../Api/appointmentsApi.js"; import {Grid} from "antd"; import {useUploadAppointmentFileMutation} from "../../../Api/appointmentFilesApi.js"; import Compressor from 'compressorjs'; -import CONFIG from "../../../Core/сonfig.js"; -import axios from "axios"; const {useBreakpoint} = Grid; @@ -299,36 +297,15 @@ const useAppointmentFormModalUI = (createAppointment, patients, cancelAppointmen for (const file of draftFiles) { try { - console.log(`Uploading file: ${file.name}, size: ${file.size}, type: ${file.type}`); - - // Формируем FormData - const formData = new FormData(); - formData.append("file", file); - - // Логируем содержимое FormData - for (let [key, value] of formData.entries()) { - console.log(`FormData entry: ${key}=${value.name || value}`); - } - - // Отправляем запрос через Axios - const uploadResponse = await axios.post( - `${CONFIG.BASE_URL}/appointment_files/${response.id}/upload/`, - formData, - { - headers: { - Authorization: `Bearer ${localStorage.getItem("access_token")}`, - // Content-Type не указываем, Axios автоматически установит multipart/form-data - }, - } - ); - - console.log(`Successfully uploaded file: ${file.name}`, uploadResponse.data); + await uploadAppointmentFile({ + appointmentId: response.id, + file: file, + }).unwrap(); } catch (error) { console.error(`Error uploading file ${file.name}:`, error); - // Улучшенная обработка ошибок - const errorMessage = error.response?.data?.detail - ? JSON.stringify(error.response.data.detail, null, 2) - : error.message || "Неизвестная ошибка"; + const errorMessage = error.data?.detail + ? JSON.stringify(error.data.detail, null, 2) + : JSON.stringify(error.data || error.message || "Неизвестная ошибка", null, 2); notification.error({ message: "Ошибка загрузки файла", description: `Не удалось загрузить файл ${file.name}: ${errorMessage}`, @@ -353,8 +330,8 @@ const useAppointmentFormModalUI = (createAppointment, patients, cancelAppointmen } catch (error) { console.error("Error creating appointment:", error); notification.error({ - message: "Ошибка", - description: error.data?.message || "Не удалось создать прием.", + message: "Ошибка загрузки файла", + description: `Не удалось загрузить файл ${JSON.stringify(error.data?.detail || error.data || error.message || "Неизвестная ошибка", null, 2)}`, placement: "topRight", }); }