Удалена дублирующая форма загрузки фото в форме создания товара

This commit is contained in:
2025-11-30 19:01:12 +03:00
parent f483b04488
commit e5b37dcd81

View File

@@ -537,226 +537,6 @@
<hr class="my-4">
<!-- Блок 3: Фотографии -->
<div class="mb-4 p-3 bg-light rounded">
<h5 class="mb-3">Фотографии</h5>
<!-- Существующие фотографии (только при редактировании) -->
{% if object and product_photos %}
<div class="mb-3">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0">Текущие фотографии (<span id="photos-count">{{ photos_count }}</span>)</h6>
<button type="button" id="delete-selected-btn" class="btn btn-danger btn-sm" style="display: none;">
🗑️ Удалить отмеченные (<span id="selected-count">0</span>)
</button>
</div>
<div class="row g-2 mb-3" id="photos-grid">
{% for photo in product_photos %}
<div class="col-md-3 col-sm-4 col-6 photo-card" data-photo-id="{{ photo.pk }}">
<div class="card shadow-sm h-100 position-relative">
<!-- Чекбокс для выбора -->
<div class="position-absolute" style="top: 5px; left: 5px; z-index: 10;">
<input type="checkbox" class="form-check-input photo-checkbox"
data-photo-id="{{ photo.pk }}"
style="width: 20px; height: 20px; cursor: pointer;">
</div>
<!-- Кликабельное фото для открытия модального окна -->
<div style="width: 100%; height: 150px; display: flex; align-items: center; justify-content: center; background-color: #f8f9fa; cursor: pointer; overflow: hidden;"
data-bs-toggle="modal"
data-bs-target="#photoModal{{ photo.pk }}"
title="Нажмите для увеличения">
<img src="{{ photo.image.url }}"
alt="Фото товара"
style="max-width: 100%; max-height: 100%; object-fit: contain;">
</div>
<div class="card-body p-2">
{% if photo.order == 0 %}
<div class="badge bg-success w-100 mb-1">⭐ Главное</div>
{% else %}
<a href="{% url 'products:product-photo-set-main' photo.pk %}"
class="btn btn-outline-primary btn-sm w-100 mb-1 py-0"
title="Сделать главным">
⭐ Главным
</a>
{% endif %}
<div class="btn-group w-100 mb-1" role="group">
<a href="{% url 'products:product-photo-move-up' photo.pk %}"
class="btn btn-outline-secondary btn-sm py-0"
title="Переместить вверх">
⬆️
</a>
<a href="{% url 'products:product-photo-move-down' photo.pk %}"
class="btn btn-outline-secondary btn-sm py-0"
title="Переместить вниз">
⬇️
</a>
</div>
<a href="{% url 'products:product-photo-delete' photo.pk %}"
class="btn btn-danger btn-sm w-100 py-0"
onclick="return confirm('Удалить это фото?');">
🗑️ Удалить
</a>
<small class="text-muted d-block mt-1 text-center">
{% if photo.order == 0 %}
Главное (позиция 1)
{% else %}
Позиция: {{ photo.order|add:1 }}
{% endif %}
</small>
</div>
</div>
</div>
<!-- Модальное окно для просмотра фото -->
<div class="modal fade" id="photoModal{{ photo.pk }}" tabindex="-1" aria-labelledby="photoModalLabel{{ photo.pk }}" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="photoModalLabel{{ photo.pk }}">Фото товара</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-body text-center">
<img src="{{ photo.image.url }}" class="img-fluid" alt="Фото товара" style="max-height: 70vh;">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
<a href="{% url 'products:product-photo-delete' photo.pk %}"
class="btn btn-danger"
onclick="return confirm('Удалить это фото?');">
🗑️ Удалить фото
</a>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- JavaScript для массового удаления фотографий -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const deleteBtn = document.getElementById('delete-selected-btn');
const selectedCount = document.getElementById('selected-count');
const photosCount = document.getElementById('photos-count');
const checkboxes = document.querySelectorAll('.photo-checkbox');
// Обновляем счётчик выбранных и видимость кнопки
function updateUI() {
const checked = document.querySelectorAll('.photo-checkbox:checked').length;
selectedCount.textContent = checked;
deleteBtn.style.display = checked > 0 ? 'block' : 'none';
}
// Обработчик для каждого чекбокса
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', updateUI);
});
// Обработчик кнопки удаления
deleteBtn.addEventListener('click', function() {
const checked = document.querySelectorAll('.photo-checkbox:checked');
if (checked.length === 0) return;
const photoIds = Array.from(checked).map(cb => cb.dataset.photoId);
const count = photoIds.length;
if (!confirm(`Вы уверены что хотите удалить ${count} фото? Это действие необратимо.`)) {
return;
}
deleteBtn.disabled = true;
deleteBtn.innerHTML = '⏳ Удаляю...';
// AJAX запрос на удаление
fetch('{% url "products:product-photos-delete-bulk" %}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
},
body: JSON.stringify({
photo_ids: photoIds
})
})
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(data => {
if (data.success) {
// Удаляем карточки фотографий из DOM
photoIds.forEach(photoId => {
const card = document.querySelector(`[data-photo-id="${photoId}"]`);
if (card) card.remove();
});
// Обновляем счётчик фотографий
const newCount = parseInt(photosCount.textContent) - count;
photosCount.textContent = newCount;
// Скрываем блок если фотографий больше нет
if (newCount === 0) {
document.querySelector('[id="photos-count"]').closest('.mb-3').parentElement.style.display = 'none';
}
// Показываем сообщение об успехе
const alert = document.createElement('div');
alert.className = 'alert alert-success alert-dismissible fade show';
alert.innerHTML = `${data.deleted} фото успешно удалено!
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>`;
document.querySelector('.mb-4.p-3.bg-light.rounded').insertAdjacentElement('beforebegin', alert);
// Скрываем кнопку
deleteBtn.style.display = 'none';
selectedCount.textContent = '0';
} else {
throw new Error(data.error || 'Неизвестная ошибка');
}
})
.catch(error => {
alert('Ошибка при удалении: ' + error.message);
console.error(error);
})
.finally(() => {
deleteBtn.disabled = false;
deleteBtn.innerHTML = '🗑️ Удалить отмеченные (<span id="selected-count">' + selectedCount.textContent + '</span>)';
});
});
});
</script>
{% endif %}
<!-- Поле для загрузки новых фотографий -->
<div class="alert alert-info border-0 shadow-sm mb-0">
<div class="d-flex align-items-center mb-2">
<i class="bi bi-cloud-upload fs-4 me-2"></i>
<label for="id_photos" class="form-label fw-bold mb-0">
{% if object %}
<i class="bi bi-plus-circle"></i> Добавить новые фото
{% else %}
<i class="bi bi-upload"></i> Загрузить фото
{% endif %}
</label>
</div>
<input type="file" name="photos" accept="image/*" multiple class="form-control form-control-lg shadow-sm" id="id_photos">
<small class="form-text text-muted d-block mt-2">
<i class="bi bi-info-circle"></i>
{% if object %}
Выберите фото для добавления к товару (можно выбрать несколько, до 10 штук всего)
{% else %}
Выберите фото для товара (можно выбрать несколько, до 10 штук)
{% endif %}
</small>
</div>
</div>
<hr class="my-4">
<div class="d-flex justify-content-between mt-4 gap-2 flex-wrap">
<div>
<a href="{% url 'products:products-list' %}" class="btn btn-secondary">Отмена</a>