361 lines
15 KiB
Plaintext
361 lines
15 KiB
Plaintext
<!-- Content Header (Page header) -->
|
|
<section class="content-header">
|
|
<div class="container-fluid">
|
|
<div class="row mb-2">
|
|
<div class="col-sm-6">
|
|
<h1><i class="fas fa-images mr-2"></i>Редактор Баннеров</h1>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<ol class="breadcrumb float-sm-right">
|
|
<li class="breadcrumb-item"><a href="/admin">Админ</a></li>
|
|
<li class="breadcrumb-item active">Баннеры</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Main content -->
|
|
<section class="content">
|
|
<div class="container-fluid">
|
|
<!-- Banner Upload Card -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">Загрузить новый баннер</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="upload-zone p-4 text-center border-2 border-dashed border-gray-300 rounded"
|
|
ondrop="handleDrop(event)" ondragover="handleDragOver(event)" ondragleave="handleDragLeave(event)">
|
|
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i>
|
|
<p class="h5 text-muted mb-2">Перетащите изображения сюда или нажмите для выбора</p>
|
|
<p class="text-muted">Поддерживаются: JPG, PNG, GIF (максимум 10MB)</p>
|
|
<input type="file" id="banner-upload" multiple accept="image/*" class="d-none">
|
|
<button type="button" class="btn btn-primary mt-3" onclick="document.getElementById('banner-upload').click()">
|
|
<i class="fas fa-plus mr-1"></i>Выбрать файлы
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Current Banners Card -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title">Текущие баннеры</h3>
|
|
<div class="card-tools">
|
|
<button class="btn btn-sm btn-default" onclick="loadBanners()">
|
|
<i class="fas fa-sync-alt"></i> Обновить
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="banners-list" class="row">
|
|
<!-- Banners will be loaded here -->
|
|
</div>
|
|
|
|
<!-- Empty state -->
|
|
<div id="empty-state" class="text-center py-5" style="display: none;">
|
|
<i class="fas fa-images fa-4x text-muted mb-3"></i>
|
|
<h4 class="text-muted">Нет загруженных баннеров</h4>
|
|
<p class="text-muted">Загрузите ваши первые баннеры используя форму выше</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Banner Edit Modal -->
|
|
<div class="modal fade" id="edit-banner-modal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-lg" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Редактировать баннер</h4>
|
|
<button type="button" class="close" data-dismiss="modal">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
<form id="edit-banner-form">
|
|
<div class="modal-body">
|
|
<input type="hidden" id="edit-banner-id">
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<img id="edit-banner-preview" src="" alt="Banner preview" class="img-fluid rounded">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="edit-banner-title">Заголовок</label>
|
|
<input type="text" class="form-control" id="edit-banner-title" name="title" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="edit-banner-subtitle">Подзаголовок</label>
|
|
<input type="text" class="form-control" id="edit-banner-subtitle" name="subtitle">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="edit-banner-description">Описание</label>
|
|
<textarea class="form-control" id="edit-banner-description" name="description" rows="3"></textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="edit-banner-button-text">Текст кнопки</label>
|
|
<input type="text" class="form-control" id="edit-banner-button-text" name="buttonText">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="edit-banner-button-url">Ссылка кнопки</label>
|
|
<input type="url" class="form-control" id="edit-banner-button-url" name="buttonUrl">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="edit-banner-order">Порядок отображения</label>
|
|
<input type="number" class="form-control" id="edit-banner-order" name="order" min="0">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<div class="custom-control custom-switch">
|
|
<input type="checkbox" class="custom-control-input" id="edit-banner-active" name="active">
|
|
<label class="custom-control-label" for="edit-banner-active">Активен</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Отмена</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save mr-1"></i>Сохранить
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.upload-zone.dragover {
|
|
border-color: #007bff !important;
|
|
background-color: #f8f9fa !important;
|
|
}
|
|
.banner-item {
|
|
transition: transform 0.2s;
|
|
}
|
|
.banner-item:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
let banners = [];
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadBanners();
|
|
|
|
// Setup file upload
|
|
document.getElementById('banner-upload').addEventListener('change', handleFileSelect);
|
|
|
|
// Setup edit form
|
|
document.getElementById('edit-banner-form').addEventListener('submit', saveBanner);
|
|
});
|
|
|
|
async function loadBanners() {
|
|
try {
|
|
const response = await fetch('/api/admin/banners');
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
banners = data.banners;
|
|
renderBanners();
|
|
} else {
|
|
throw new Error(data.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading banners:', error);
|
|
alert('Ошибка загрузки баннеров: ' + error.message);
|
|
}
|
|
}
|
|
|
|
function renderBanners() {
|
|
const container = document.getElementById('banners-list');
|
|
const emptyState = document.getElementById('empty-state');
|
|
|
|
if (banners.length === 0) {
|
|
container.innerHTML = '';
|
|
emptyState.style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
emptyState.style.display = 'none';
|
|
|
|
container.innerHTML = banners.map(banner => `
|
|
<div class="col-md-4 mb-4">
|
|
<div class="card banner-item">
|
|
<img src="${banner.imageUrl}" class="card-img-top" style="height: 200px; object-fit: cover;">
|
|
<div class="card-body">
|
|
<h5 class="card-title">${banner.title || 'Без названия'}</h5>
|
|
<p class="card-text text-muted small">${banner.subtitle || ''}</p>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="btn-group">
|
|
<button class="btn btn-sm btn-outline-primary" onclick="editBanner('${banner._id}')">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-danger" onclick="deleteBanner('${banner._id}')">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
<small class="text-muted">
|
|
${banner.active ? '<span class="badge badge-success">Активен</span>' : '<span class="badge badge-secondary">Неактивен</span>'}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
function handleDragOver(event) {
|
|
event.preventDefault();
|
|
event.currentTarget.classList.add('dragover');
|
|
}
|
|
|
|
function handleDragLeave(event) {
|
|
event.preventDefault();
|
|
event.currentTarget.classList.remove('dragover');
|
|
}
|
|
|
|
function handleDrop(event) {
|
|
event.preventDefault();
|
|
event.currentTarget.classList.remove('dragover');
|
|
|
|
const files = Array.from(event.dataTransfer.files);
|
|
uploadFiles(files);
|
|
}
|
|
|
|
function handleFileSelect(event) {
|
|
const files = Array.from(event.target.files);
|
|
uploadFiles(files);
|
|
event.target.value = ''; // Reset input
|
|
}
|
|
|
|
async function uploadFiles(files) {
|
|
for (const file of files) {
|
|
if (!file.type.startsWith('image/')) {
|
|
alert(`Файл ${file.name} не является изображением`);
|
|
continue;
|
|
}
|
|
|
|
if (file.size > 10 * 1024 * 1024) { // 10MB
|
|
alert(`Файл ${file.name} слишком большой (максимум 10MB)`);
|
|
continue;
|
|
}
|
|
|
|
await uploadFile(file);
|
|
}
|
|
|
|
loadBanners(); // Refresh the list
|
|
}
|
|
|
|
async function uploadFile(file) {
|
|
const formData = new FormData();
|
|
formData.append('banner', file);
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/banners/upload', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.success) {
|
|
throw new Error(data.message);
|
|
}
|
|
|
|
console.log(`Файл ${file.name} успешно загружен`);
|
|
} catch (error) {
|
|
console.error(`Error uploading ${file.name}:`, error);
|
|
alert(`Ошибка загрузки ${file.name}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
function editBanner(bannerId) {
|
|
const banner = banners.find(b => b._id === bannerId);
|
|
if (!banner) return;
|
|
|
|
// Fill the form
|
|
document.getElementById('edit-banner-id').value = banner._id;
|
|
document.getElementById('edit-banner-preview').src = banner.imageUrl;
|
|
document.getElementById('edit-banner-title').value = banner.title || '';
|
|
document.getElementById('edit-banner-subtitle').value = banner.subtitle || '';
|
|
document.getElementById('edit-banner-description').value = banner.description || '';
|
|
document.getElementById('edit-banner-button-text').value = banner.buttonText || '';
|
|
document.getElementById('edit-banner-button-url').value = banner.buttonUrl || '';
|
|
document.getElementById('edit-banner-order').value = banner.order || 0;
|
|
document.getElementById('edit-banner-active').checked = banner.active || false;
|
|
|
|
// Show modal
|
|
$('#edit-banner-modal').modal('show');
|
|
}
|
|
|
|
async function saveBanner(event) {
|
|
event.preventDefault();
|
|
|
|
const formData = new FormData(event.target);
|
|
const bannerId = document.getElementById('edit-banner-id').value;
|
|
|
|
const bannerData = {
|
|
title: formData.get('title'),
|
|
subtitle: formData.get('subtitle'),
|
|
description: formData.get('description'),
|
|
buttonText: formData.get('buttonText'),
|
|
buttonUrl: formData.get('buttonUrl'),
|
|
order: parseInt(formData.get('order')) || 0,
|
|
active: formData.has('active')
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(`/api/admin/banners/${bannerId}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(bannerData)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
$('#edit-banner-modal').modal('hide');
|
|
loadBanners();
|
|
alert('Баннер обновлен');
|
|
} else {
|
|
throw new Error(data.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error saving banner:', error);
|
|
alert('Ошибка сохранения баннера: ' + error.message);
|
|
}
|
|
}
|
|
|
|
async function deleteBanner(bannerId) {
|
|
if (!confirm('Вы уверены, что хотите удалить этот баннер?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/admin/banners/${bannerId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
loadBanners();
|
|
alert('Баннер удален');
|
|
} else {
|
|
throw new Error(data.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error deleting banner:', error);
|
|
alert('Ошибка удаления баннера: ' + error.message);
|
|
}
|
|
}
|
|
</script> |