- Portfolio CRUD: добавление, редактирование, удаление, переключение публикации - Services CRUD: полное управление услугами с возможностью активации/деактивации - Banner system: новая модель Banner с CRUD операциями и аналитикой кликов - Telegram integration: расширенные настройки бота, обнаружение чатов, отправка сообщений - Media management: улучшенная загрузка файлов с оптимизацией изображений и превью - UI improvements: обновлённые админ-панели с rich-text редактором и drag&drop загрузкой - Database: добавлена таблица banners с полями для баннеров и аналитики
350 lines
19 KiB
Plaintext
350 lines
19 KiB
Plaintext
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Настройки сайта - SmartSolTech Admin</title>
|
||
|
||
<!-- Tailwind CSS -->
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
|
||
<!-- Font Awesome -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
|
||
<!-- Custom CSS -->
|
||
<link rel="stylesheet" href="/css/main.css">
|
||
<link rel="stylesheet" href="/css/fixes.css">
|
||
</head>
|
||
<body class="bg-gray-100">
|
||
<!-- Admin Header -->
|
||
<header class="bg-white shadow-sm border-b">
|
||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div class="flex justify-between items-center h-16">
|
||
<div class="flex items-center">
|
||
<h1 class="text-xl font-semibold text-gray-900">
|
||
<i class="fas fa-cogs mr-2"></i>
|
||
SmartSolTech Admin
|
||
</h1>
|
||
</div>
|
||
<div class="flex items-center space-x-4">
|
||
<span class="text-sm text-gray-600">
|
||
Добро пожаловать, <%= user ? user.name : 'Admin' %>!
|
||
</span>
|
||
<a href="/" class="text-gray-500 hover:text-gray-700">
|
||
<i class="fas fa-external-link-alt mr-1"></i>
|
||
Посмотреть сайт
|
||
</a>
|
||
<form action="/admin/logout" method="post" class="inline">
|
||
<button type="submit" class="text-red-600 hover:text-red-800">
|
||
<i class="fas fa-sign-out-alt mr-1"></i>
|
||
Выход
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="flex">
|
||
<!-- Admin Sidebar -->
|
||
<aside class="w-64 bg-white shadow-sm admin-sidebar min-h-screen">
|
||
<nav class="mt-5 px-2">
|
||
<div class="space-y-1">
|
||
<a href="/admin/dashboard" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fas fa-tachometer-alt mr-3"></i>
|
||
Панель управления
|
||
</a>
|
||
<a href="/admin/portfolio" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fas fa-briefcase mr-3"></i>
|
||
Портфолио
|
||
</a>
|
||
<a href="/admin/services" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fas fa-cog mr-3"></i>
|
||
Услуги
|
||
</a>
|
||
<a href="/admin/contacts" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fas fa-envelope mr-3"></i>
|
||
Сообщения
|
||
</a>
|
||
<a href="/admin/media" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fas fa-images mr-3"></i>
|
||
Медиа
|
||
</a>
|
||
<a href="/admin/settings" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md bg-blue-100 text-blue-700">
|
||
<i class="fas fa-cogs mr-3"></i>
|
||
Настройки
|
||
</a>
|
||
<a href="/admin/telegram" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fab fa-telegram mr-3"></i>
|
||
Telegram Bot
|
||
</a>
|
||
<a href="/admin/banner-editor" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-600 hover:bg-gray-50 hover:text-gray-900">
|
||
<i class="fas fa-paint-brush mr-3"></i>
|
||
Редактор баннеров
|
||
</a>
|
||
</div>
|
||
</nav>
|
||
</aside>
|
||
|
||
<!-- Main Content -->
|
||
<main class="flex-1 p-8">
|
||
<div class="space-y-6">
|
||
<!-- Header -->
|
||
<div class="bg-white shadow rounded-lg p-6">
|
||
<h1 class="text-2xl font-bold text-gray-900 flex items-center">
|
||
<i class="fas fa-cogs mr-3 text-blue-600"></i>
|
||
Настройки сайта
|
||
</h1>
|
||
<p class="mt-2 text-gray-600">Управление основными параметрами сайта</p>
|
||
</div>
|
||
|
||
<!-- Site Settings -->
|
||
<div class="bg-white shadow rounded-lg">
|
||
<div class="px-4 py-5 sm:px-6 border-b border-gray-200">
|
||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||
<i class="fas fa-cogs mr-2"></i>
|
||
Настройки сайта
|
||
</h3>
|
||
</div>
|
||
|
||
<form id="settingsForm" class="p-6">
|
||
<div class="space-y-8">
|
||
<!-- Basic Settings -->
|
||
<div>
|
||
<h4 class="text-lg font-medium text-gray-900 mb-4">Основные настройки</h4>
|
||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div class="sm:col-span-2">
|
||
<label for="siteName" class="block text-sm font-medium text-gray-700">Название сайта</label>
|
||
<input type="text" name="siteName" id="siteName"
|
||
value="<%= settings.siteName || 'SmartSolTech' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div class="sm:col-span-2">
|
||
<label for="siteDescription" class="block text-sm font-medium text-gray-700">Описание сайта</label>
|
||
<textarea name="siteDescription" id="siteDescription" rows="3"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"><%= settings.siteDescription || '' %></textarea>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="logo" class="block text-sm font-medium text-gray-700">Логотип</label>
|
||
<input type="file" name="logo" id="logo" accept="image/*"
|
||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
||
<% if (settings.logo) { %>
|
||
<img src="<%= settings.logo %>" alt="Current logo" class="mt-2 h-16 w-auto">
|
||
<% } %>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="favicon" class="block text-sm font-medium text-gray-700">Favicon</label>
|
||
<input type="file" name="favicon" id="favicon" accept="image/*"
|
||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
||
<% if (settings.favicon) { %>
|
||
<img src="<%= settings.favicon %>" alt="Current favicon" class="mt-2 h-8 w-8">
|
||
<% } %>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Contact Information -->
|
||
<div>
|
||
<h4 class="text-lg font-medium text-gray-900 mb-4">Контактная информация</h4>
|
||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div>
|
||
<label for="contactEmail" class="block text-sm font-medium text-gray-700">Email</label>
|
||
<input type="email" name="contact.email" id="contactEmail"
|
||
value="<%= settings.contact?.email || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div>
|
||
<label for="contactPhone" class="block text-sm font-medium text-gray-700">Телефон</label>
|
||
<input type="tel" name="contact.phone" id="contactPhone"
|
||
value="<%= settings.contact?.phone || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div class="sm:col-span-2">
|
||
<label for="contactAddress" class="block text-sm font-medium text-gray-700">Адрес</label>
|
||
<textarea name="contact.address" id="contactAddress" rows="2"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"><%= settings.contact?.address || '' %></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Social Media -->
|
||
<div>
|
||
<h4 class="text-lg font-medium text-gray-900 mb-4">Социальные сети</h4>
|
||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div>
|
||
<label for="socialFacebook" class="block text-sm font-medium text-gray-700">Facebook</label>
|
||
<input type="url" name="social.facebook" id="socialFacebook"
|
||
value="<%= settings.social?.facebook || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div>
|
||
<label for="socialTwitter" class="block text-sm font-medium text-gray-700">Twitter</label>
|
||
<input type="url" name="social.twitter" id="socialTwitter"
|
||
value="<%= settings.social?.twitter || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div>
|
||
<label for="socialInstagram" class="block text-sm font-medium text-gray-700">Instagram</label>
|
||
<input type="url" name="social.instagram" id="socialInstagram"
|
||
value="<%= settings.social?.instagram || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div>
|
||
<label for="socialLinkedin" class="block text-sm font-medium text-gray-700">LinkedIn</label>
|
||
<input type="url" name="social.linkedin" id="socialLinkedin"
|
||
value="<%= settings.social?.linkedin || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Telegram Bot Settings -->
|
||
<div>
|
||
<h4 class="text-lg font-medium text-gray-900 mb-4">Telegram Bot</h4>
|
||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||
<div>
|
||
<label for="telegramBotToken" class="block text-sm font-medium text-gray-700">Bot Token</label>
|
||
<input type="text" name="telegram.botToken" id="telegramBotToken"
|
||
value="<%= settings.telegram?.botToken || '' %>"
|
||
placeholder="123456789:AABBccDDeeFFggHHiiJJkkLLmmNNooP"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
<p class="mt-1 text-sm text-gray-500">Получите токен у @BotFather</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="telegramChatId" class="block text-sm font-medium text-gray-700">Chat ID</label>
|
||
<input type="text" name="telegram.chatId" id="telegramChatId"
|
||
value="<%= settings.telegram?.chatId || '' %>"
|
||
placeholder="-123456789"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
<p class="mt-1 text-sm text-gray-500">ID чата для уведомлений</p>
|
||
</div>
|
||
|
||
<div class="sm:col-span-2">
|
||
<button type="button" id="testTelegram" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md text-sm font-medium">
|
||
<i class="fab fa-telegram-plane mr-1"></i>
|
||
Проверить соединение
|
||
</button>
|
||
<div id="telegramStatus" class="mt-2"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SEO Settings -->
|
||
<div>
|
||
<h4 class="text-lg font-medium text-gray-900 mb-4">SEO настройки</h4>
|
||
<div class="space-y-4">
|
||
<div>
|
||
<label for="seoTitle" class="block text-sm font-medium text-gray-700">Meta Title</label>
|
||
<input type="text" name="seo.title" id="seoTitle"
|
||
value="<%= settings.seo?.title || '' %>"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
|
||
<div>
|
||
<label for="seoDescription" class="block text-sm font-medium text-gray-700">Meta Description</label>
|
||
<textarea name="seo.description" id="seoDescription" rows="3"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"><%= settings.seo?.description || '' %></textarea>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="seoKeywords" class="block text-sm font-medium text-gray-700">Keywords</label>
|
||
<input type="text" name="seo.keywords" id="seoKeywords"
|
||
value="<%= settings.seo?.keywords || '' %>"
|
||
placeholder="веб-разработка, мобильные приложения, дизайн"
|
||
class="mt-1 block w-full border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Submit Button -->
|
||
<div class="mt-8 flex justify-end">
|
||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
|
||
<i class="fas fa-save mr-1"></i>
|
||
Сохранить настройки
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<script>
|
||
document.getElementById('settingsForm').addEventListener('submit', async function(e) {
|
||
e.preventDefault();
|
||
|
||
const formData = new FormData(this);
|
||
|
||
try {
|
||
const response = await fetch('/api/admin/settings', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
alert('Настройки успешно сохранены');
|
||
location.reload();
|
||
} else {
|
||
alert('Ошибка при сохранении настроек: ' + data.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error:', error);
|
||
alert('Ошибка при сохранении настроек');
|
||
}
|
||
});
|
||
|
||
// Test Telegram connection
|
||
document.getElementById('testTelegram').addEventListener('click', async function() {
|
||
const botToken = document.getElementById('telegramBotToken').value;
|
||
const chatId = document.getElementById('telegramChatId').value;
|
||
const statusDiv = document.getElementById('telegramStatus');
|
||
|
||
if (!botToken || !chatId) {
|
||
statusDiv.innerHTML = '<p class="text-red-600">Пожалуйста, заполните Bot Token и Chat ID</p>';
|
||
return;
|
||
}
|
||
|
||
this.disabled = true;
|
||
this.innerHTML = '<i class="fas fa-spinner fa-spin mr-1"></i> Проверка...';
|
||
|
||
try {
|
||
const response = await fetch('/api/admin/telegram/test', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ botToken, chatId })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
statusDiv.innerHTML = '<p class="text-green-600"><i class="fas fa-check mr-1"></i> Соединение установлено успешно!</p>';
|
||
} else {
|
||
statusDiv.innerHTML = `<p class="text-red-600"><i class="fas fa-times mr-1"></i> Ошибка: ${data.message}</p>`;
|
||
}
|
||
} catch (error) {
|
||
statusDiv.innerHTML = '<p class="text-red-600"><i class="fas fa-times mr-1"></i> Ошибка соединения</p>';
|
||
}
|
||
|
||
this.disabled = false;
|
||
this.innerHTML = '<i class="fab fa-telegram-plane mr-1"></i> Проверить соединение';
|
||
});
|
||
</script>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<!-- JavaScript -->
|
||
<script src="/js/main.js"></script>
|
||
</body>
|
||
</html> |