фикс фоток
This commit is contained in:
parent
fbcf49a3a6
commit
118597a73c
@ -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;
|
||||
|
@ -122,16 +122,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Photos Section -->
|
||||
</div> <!-- Photos Section -->
|
||||
<div class="info-card" id="photos-section">
|
||||
<div class="card-header">
|
||||
<h3><i class="bi-images"></i> Мои фотографии</h3>
|
||||
<div class="header-actions" v-if="isEditMode">
|
||||
<button class="add-photo-btn" @click="triggerPhotoUpload">
|
||||
<i class="bi-plus"></i>
|
||||
Добавить фото
|
||||
<h3><i class="bi-images"></i> Мои фотографии</h3> <div class="header-actions">
|
||||
<button class="add-photo-btn" @click="triggerPhotoUpload" :disabled="photoActionLoading">
|
||||
<span v-if="photoActionLoading" class="spinner-small"></span>
|
||||
<i v-else class="bi-plus"></i>
|
||||
{{ photoActionLoading ? 'Загрузка...' : 'Добавить фото' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -170,18 +168,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div v-else class="empty-photos">
|
||||
<!-- Empty State --> <div v-else class="empty-photos">
|
||||
<i class="bi-image"></i>
|
||||
<h4>Нет фотографий</h4>
|
||||
<p>Добавьте фотографии, чтобы сделать профиль привлекательнее</p>
|
||||
<button v-if="isEditMode" class="action-btn primary" @click="triggerPhotoUpload">
|
||||
<i class="bi-plus"></i>
|
||||
Добавить первое фото
|
||||
<button class="action-btn primary" @click="triggerPhotoUpload" :disabled="photoActionLoading">
|
||||
<span v-if="photoActionLoading" class="spinner-small"></span>
|
||||
<i v-else class="bi-plus"></i>
|
||||
{{ photoActionLoading ? 'Загрузка...' : 'Добавить первое фото' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Photo Messages -->
|
||||
<!-- Photo Messages -->
|
||||
<div v-if="photoActionError" class="alert error">
|
||||
<i class="bi-exclamation-circle"></i>
|
||||
{{ photoActionError }}
|
||||
@ -190,6 +187,10 @@
|
||||
<i class="bi-check-circle"></i>
|
||||
{{ photoActionSuccess }}
|
||||
</div>
|
||||
<div v-if="photoActionLoading" class="alert info">
|
||||
<div class="spinner-small" style="border-top-color:#667eea"></div>
|
||||
Загрузка фотографий...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -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;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user