Files
sst_site/views/admin/banner-editor.ejs
2025-10-26 22:14:47 +09:00

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>&times;</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>