AdminLTE3
This commit is contained in:
361
.history/views/admin/banner-editor_20251026215001.ejs
Normal file
361
.history/views/admin/banner-editor_20251026215001.ejs
Normal file
@@ -0,0 +1,361 @@
|
||||
<!-- 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>
|
||||
Reference in New Issue
Block a user