From 118597a73c4f169c67709fb71383e46c3490daac Mon Sep 17 00:00:00 2001
From: 107 <107@DESKTOP-UP8U7M2>
Date: Fri, 23 May 2025 13:16:13 +0700
Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=84=D0=BE=D1=82?=
=?UTF-8?q?=D0=BE=D0=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/EditProfileForm.vue | 31 +++++
src/views/ProfileView.vue | 194 ++++++++++++++++++++++++++---
2 files changed, 207 insertions(+), 18 deletions(-)
diff --git a/src/components/EditProfileForm.vue b/src/components/EditProfileForm.vue
index 1209e63..7b92209 100644
--- a/src/components/EditProfileForm.vue
+++ b/src/components/EditProfileForm.vue
@@ -411,6 +411,37 @@ const handlePhotoUpload = async (files) => {
console.log(`[EditProfileForm] handlePhotoUpload: получено файлов: ${files.length}`);
+ // Проверяем форматы и размеры файлов
+ const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/jpg'];
+ const maxSizeMB = 10; // Максимальный размер файла в MB
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
+
+ let hasInvalidType = false;
+ let hasInvalidSize = false;
+
+ for (const file of files) {
+ if (!allowedTypes.includes(file.type)) {
+ hasInvalidType = true;
+ break;
+ }
+ if (file.size > maxSizeBytes) {
+ hasInvalidSize = true;
+ break;
+ }
+ }
+
+ if (hasInvalidType) {
+ photoUploadErrorMessage.value = 'Можно загружать только фотографии (JPEG, PNG, WebP)';
+ emit('photo-upload-complete', { success: 0, errors: files.length });
+ return;
+ }
+
+ if (hasInvalidSize) {
+ photoUploadErrorMessage.value = `Размер файла не должен превышать ${maxSizeMB} МБ`;
+ emit('photo-upload-complete', { success: 0, errors: files.length });
+ return;
+ }
+
// Индикатор для отслеживания успешных загрузок
let successCount = 0;
let errorCount = 0;
diff --git a/src/views/ProfileView.vue b/src/views/ProfileView.vue
index 8666fae..9f71b84 100644
--- a/src/views/ProfileView.vue
+++ b/src/views/ProfileView.vue
@@ -122,16 +122,14 @@
-
-
-
+
-
-
+
Нет фотографий
Добавьте фотографии, чтобы сделать профиль привлекательнее
-
-
-
+
{{ photoActionError }}
@@ -190,6 +187,10 @@
{{ photoActionSuccess }}
+
+
+ Загрузка фотографий...
+
@@ -306,6 +307,7 @@ const scrollToEdit = () => {
const triggerPhotoUpload = () => {
if (fileInput.value) {
+ clearMessages(); // Очищаем предыдущие сообщения перед новой загрузкой
fileInput.value.click();
}
};
@@ -313,10 +315,43 @@ const triggerPhotoUpload = () => {
const handlePhotoSelect = async (event) => {
const files = event.target.files;
if (!files || files.length === 0) return;
-
- // Передаем выбранные файлы в форму редактирования
- if (editFormRef.value && editFormRef.value.handlePhotoUpload) {
+ // Проверяем форматы и размеры файлов
+ const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/jpg'];
+ const maxSizeMB = 10; // Максимальный размер файла в MB
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
+
+ let hasInvalidType = false;
+ let hasInvalidSize = false;
+
+ for (const file of files) {
+ if (!allowedTypes.includes(file.type)) {
+ hasInvalidType = true;
+ break;
+ }
+ if (file.size > maxSizeBytes) {
+ hasInvalidSize = true;
+ break;
+ }
+ }
+
+ if (hasInvalidType) {
+ photoActionError.value = 'Можно загружать только фотографии (JPEG, PNG, WebP)';
+ event.target.value = '';
+ return;
+ }
+
+ if (hasInvalidSize) {
+ photoActionError.value = `Размер файла не должен превышать ${maxSizeMB} МБ`;
+ event.target.value = '';
+ return;
+ }
+
+ // Если активна форма редактирования, используем её метод
+ if (isEditMode.value && editFormRef.value && editFormRef.value.handlePhotoUpload) {
await editFormRef.value.handlePhotoUpload(Array.from(files));
+ } else {
+ // Иначе обрабатываем загрузку фото здесь
+ await uploadPhotos(Array.from(files));
}
// Очищаем input
@@ -387,6 +422,102 @@ const handlePhotoUploadComplete = (result) => {
}
};
+// Новый метод для загрузки фотографий непосредственно из ProfileView
+const uploadPhotos = async (files) => {
+ if (!files || files.length === 0) {
+ console.log('[ProfileView] uploadPhotos: нет файлов для загрузки');
+ return;
+ }
+
+ console.log(`[ProfileView] uploadPhotos: получено файлов: ${files.length}`);
+
+ // Индикатор для отслеживания успешных загрузок
+ let successCount = 0;
+ let errorCount = 0;
+ photoActionLoading.value = true;
+ clearMessages();
+ try {
+ let imageCompression;
+ try {
+ // Импортируем библиотеку для сжатия изображений динамически
+ imageCompression = (await import('browser-image-compression')).default;
+ } catch (importErr) {
+ console.error('[ProfileView] Ошибка при импорте библиотеки сжатия:', importErr);
+ throw new Error('Не удалось загрузить необходимые компоненты. Пожалуйста, обновите страницу и попробуйте снова.');
+ }
+
+ // Настройки для сжатия изображений
+ const options = {
+ maxSizeMB: 1,
+ maxWidthOrHeight: 1920,
+ useWebWorker: true,
+ };
+
+ for (let i = 0; i < files.length; i++) {
+ const originalFile = files[i];
+
+ try {
+ // Сжимаем файл
+ console.log(`[ProfileView] Сжатие файла ${originalFile.name}...`);
+ const compressedFile = await imageCompression(originalFile, options);
+ console.log(`[ProfileView] Файл ${originalFile.name} сжат. Оригинальный размер: ${(originalFile.size / 1024 / 1024).toFixed(2)} MB, Новый размер: ${(compressedFile.size / 1024 / 1024).toFixed(2)} MB`);
+
+ // Создаем FormData для отправки на сервер
+ const fd = new FormData();
+ fd.append('profilePhoto', compressedFile, originalFile.name);
+
+ // Отправляем файл
+ console.log(`[ProfileView] Отправка файла ${originalFile.name} (сжатого) на сервер...`);
+ const response = await api.uploadUserProfilePhoto(fd);
+ console.log(`[ProfileView] Ответ сервера (фото ${originalFile.name}):`, response.data);
+
+ // Увеличиваем счетчик успешных загрузок
+ successCount++;
+
+ // Обновляем данные пользователя после каждой успешной загрузки
+ await fetchUser();
+ console.log(`[ProfileView] Данные пользователя обновлены после загрузки фото ${originalFile.name}`);
+ } catch (err) {
+ console.error(`[ProfileView] Ошибка при сжатии или загрузке фото ${originalFile.name}:`, err);
+ errorCount++;
+
+ // Показываем более информативное сообщение об ошибке
+ if (err.message && err.message.includes('network')) {
+ photoActionError.value = 'Ошибка сети при загрузке фото. Пожалуйста, проверьте подключение к интернету.';
+ } else if (err.response && err.response.status === 413) {
+ photoActionError.value = 'Файл слишком большой. Пожалуйста, выберите фото меньшего размера.';
+ }
+ }
+ }
+
+ // Формируем сообщение для пользователя
+ if (successCount > 0) {
+ photoActionSuccess.value = `Успешно загружено фотографий: ${successCount}`;
+ console.log(`[ProfileView] Успешно загружено фотографий: ${successCount}`);
+
+ // Автоматически скрываем сообщение через 3 секунды
+ setTimeout(() => {
+ photoActionSuccess.value = '';
+ }, 3000);
+
+ // Прокручиваем к разделу с фотографиями
+ setTimeout(() => {
+ scrollToPhotos();
+ }, 100);
+ }
+
+ if (errorCount > 0) {
+ photoActionError.value = `Не удалось загрузить некоторые фото (${errorCount})`;
+ console.log(`[ProfileView] Ошибок при загрузке: ${errorCount}`);
+ }
+ } catch (err) {
+ console.error('[ProfileView] Общая ошибка при загрузке фото:', err);
+ photoActionError.value = 'Произошла ошибка при загрузке фотографий';
+ } finally {
+ photoActionLoading.value = false;
+ }
+};
+
const clearMessages = () => {
photoActionError.value = '';
photoActionSuccess.value = '';
@@ -959,6 +1090,9 @@ onMounted(async () => {
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
}
.add-photo-btn:hover {
@@ -966,6 +1100,11 @@ onMounted(async () => {
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
+.add-photo-btn:active {
+ transform: translateY(0);
+ box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
+}
+
.photo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
@@ -1088,6 +1227,12 @@ onMounted(async () => {
border: 1px solid rgba(40, 167, 69, 0.2);
}
+.alert.info {
+ background: rgba(102, 126, 234, 0.1);
+ color: #3c4d8d;
+ border: 1px solid rgba(102, 126, 234, 0.2);
+}
+
/* Modal */
.modal-overlay {
position: fixed;
@@ -1199,4 +1344,17 @@ onMounted(async () => {
padding: 1.5rem;
}
}
+
+/* Spinner для кнопок */
+.spinner-small {
+ width: 16px;
+ height: 16px;
+ border: 2px solid rgba(255, 255, 255, 0.3);
+ border-radius: 50%;
+ border-top-color: white;
+ animation: spin 1s ease-in-out infinite;
+ margin-right: 6px;
+ display: inline-block;
+ vertical-align: middle;
+}
\ No newline at end of file