AdminLTE3

This commit is contained in:
2025-10-26 22:14:47 +09:00
parent 291fc63a4c
commit 9974811a3e
226 changed files with 88284 additions and 3406 deletions

View File

@@ -1,280 +1,362 @@
<!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">
<!-- 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>
<!-- 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-cogs 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">
<!-- Site Information Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Основная информация</h3>
</div>
<form id="site-settings-form">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="site-title">Название сайта</label>
<input type="text" class="form-control" id="site-title" name="siteTitle" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="site-tagline">Слоган</label>
<input type="text" class="form-control" id="site-tagline" name="siteTagline">
</div>
</div>
</div>
<div class="form-group">
<label for="site-description">Описание сайта</label>
<textarea class="form-control" id="site-description" name="siteDescription" rows="3"></textarea>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="company-name">Название компании</label>
<input type="text" class="form-control" id="company-name" name="companyName" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="company-email">Email компании</label>
<input type="email" class="form-control" id="company-email" name="companyEmail" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="company-phone">Телефон</label>
<input type="tel" class="form-control" id="company-phone" name="companyPhone">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="company-address">Адрес</label>
<input type="text" class="form-control" id="company-address" name="companyAddress">
</div>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save mr-1"></i>Сохранить
</button>
</div>
</form>
</div>
<!-- SEO Settings Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">SEO настройки</h3>
</div>
<form id="seo-settings-form">
<div class="card-body">
<div class="form-group">
<label for="meta-keywords">Ключевые слова</label>
<input type="text" class="form-control" id="meta-keywords" name="metaKeywords"
placeholder="ключевое слово 1, ключевое слово 2, ...">
<small class="form-text text-muted">Разделяйте ключевые слова запятыми</small>
</div>
<div class="form-group">
<label for="meta-description">Meta Description</label>
<textarea class="form-control" id="meta-description" name="metaDescription"
rows="3" maxlength="160"></textarea>
<small class="form-text text-muted">Рекомендуемая длина: до 160 символов</small>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="google-analytics">Google Analytics ID</label>
<input type="text" class="form-control" id="google-analytics" name="googleAnalytics"
placeholder="G-XXXXXXXXXX">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="google-tag-manager">Google Tag Manager ID</label>
<input type="text" class="form-control" id="google-tag-manager" name="googleTagManager"
placeholder="GTM-XXXXXXX">
</div>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save mr-1"></i>Сохранить SEO
</button>
</div>
</form>
</div>
<!-- Social Media Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Социальные сети</h3>
</div>
<form id="social-settings-form">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="facebook-url"><i class="fab fa-facebook mr-1"></i>Facebook</label>
<input type="url" class="form-control" id="facebook-url" name="facebookUrl"
placeholder="https://facebook.com/your-page">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="twitter-url"><i class="fab fa-twitter mr-1"></i>Twitter</label>
<input type="url" class="form-control" id="twitter-url" name="twitterUrl"
placeholder="https://twitter.com/your-account">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="linkedin-url"><i class="fab fa-linkedin mr-1"></i>LinkedIn</label>
<input type="url" class="form-control" id="linkedin-url" name="linkedinUrl"
placeholder="https://linkedin.com/company/your-company">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="instagram-url"><i class="fab fa-instagram mr-1"></i>Instagram</label>
<input type="url" class="form-control" id="instagram-url" name="instagramUrl"
placeholder="https://instagram.com/your-account">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="youtube-url"><i class="fab fa-youtube mr-1"></i>YouTube</label>
<input type="url" class="form-control" id="youtube-url" name="youtubeUrl"
placeholder="https://youtube.com/channel/your-channel">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="github-url"><i class="fab fa-github mr-1"></i>GitHub</label>
<input type="url" class="form-control" id="github-url" name="githubUrl"
placeholder="https://github.com/your-account">
</div>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save mr-1"></i>Сохранить соцсети
</button>
</div>
</form>
</div>
<!-- Maintenance Mode Card -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Режим обслуживания</h3>
</div>
<div class="card-body">
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="maintenance-mode">
<label class="custom-control-label" for="maintenance-mode">
Включить режим обслуживания
</label>
</div>
<small class="form-text text-muted">
В режиме обслуживания сайт будет недоступен для обычных пользователей
</small>
</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 class="form-group">
<label for="maintenance-message">Сообщение для пользователей</label>
<textarea class="form-control" id="maintenance-message" rows="3"
placeholder="Сайт временно недоступен из-за технических работ..."></textarea>
</div>
<button type="button" class="btn btn-warning" onclick="toggleMaintenanceMode()">
<i class="fas fa-tools mr-1"></i>Применить настройки
</button>
</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>
</div>
</section>
<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
});
document.addEventListener('DOMContentLoaded', function() {
loadSettings();
const data = await response.json();
if (data.success) {
alert('Настройки успешно сохранены');
location.reload();
} else {
alert('Ошибка при сохранении настроек: ' + data.message);
}
} catch (error) {
console.error('Error:', error);
alert('Ошибка при сохранении настроек');
}
});
// Setup form submissions
document.getElementById('site-settings-form').addEventListener('submit', saveSiteSettings);
document.getElementById('seo-settings-form').addEventListener('submit', saveSeoSettings);
document.getElementById('social-settings-form').addEventListener('submit', saveSocialSettings);
});
// 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>`;
async function loadSettings() {
try {
const response = await fetch('/api/admin/settings');
const data = await response.json();
if (data.success) {
const settings = data.settings;
// Site settings
document.getElementById('site-title').value = settings.siteTitle || '';
document.getElementById('site-tagline').value = settings.siteTagline || '';
document.getElementById('site-description').value = settings.siteDescription || '';
document.getElementById('company-name').value = settings.companyName || '';
document.getElementById('company-email').value = settings.companyEmail || '';
document.getElementById('company-phone').value = settings.companyPhone || '';
document.getElementById('company-address').value = settings.companyAddress || '';
// SEO settings
document.getElementById('meta-keywords').value = settings.metaKeywords || '';
document.getElementById('meta-description').value = settings.metaDescription || '';
document.getElementById('google-analytics').value = settings.googleAnalytics || '';
document.getElementById('google-tag-manager').value = settings.googleTagManager || '';
// Social media
document.getElementById('facebook-url').value = settings.facebookUrl || '';
document.getElementById('twitter-url').value = settings.twitterUrl || '';
document.getElementById('linkedin-url').value = settings.linkedinUrl || '';
document.getElementById('instagram-url').value = settings.instagramUrl || '';
document.getElementById('youtube-url').value = settings.youtubeUrl || '';
document.getElementById('github-url').value = settings.githubUrl || '';
// Maintenance mode
document.getElementById('maintenance-mode').checked = settings.maintenanceMode || false;
document.getElementById('maintenance-message').value = settings.maintenanceMessage || '';
}
} catch (error) {
console.error('Error loading settings:', error);
alert('Ошибка загрузки настроек: ' + error.message);
}
} 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>
async function saveSiteSettings(event) {
event.preventDefault();
const formData = new FormData(event.target);
const settings = {
siteTitle: formData.get('siteTitle'),
siteTagline: formData.get('siteTagline'),
siteDescription: formData.get('siteDescription'),
companyName: formData.get('companyName'),
companyEmail: formData.get('companyEmail'),
companyPhone: formData.get('companyPhone'),
companyAddress: formData.get('companyAddress')
};
await saveSettings(settings, 'Основные настройки сохранены');
}
async function saveSeoSettings(event) {
event.preventDefault();
const formData = new FormData(event.target);
const settings = {
metaKeywords: formData.get('metaKeywords'),
metaDescription: formData.get('metaDescription'),
googleAnalytics: formData.get('googleAnalytics'),
googleTagManager: formData.get('googleTagManager')
};
await saveSettings(settings, 'SEO настройки сохранены');
}
async function saveSocialSettings(event) {
event.preventDefault();
const formData = new FormData(event.target);
const settings = {
facebookUrl: formData.get('facebookUrl'),
twitterUrl: formData.get('twitterUrl'),
linkedinUrl: formData.get('linkedinUrl'),
instagramUrl: formData.get('instagramUrl'),
youtubeUrl: formData.get('youtubeUrl'),
githubUrl: formData.get('githubUrl')
};
await saveSettings(settings, 'Настройки соцсетей сохранены');
}
async function saveSettings(settings, successMessage) {
try {
const response = await fetch('/api/admin/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(settings)
});
const data = await response.json();
if (data.success) {
alert(successMessage);
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Error saving settings:', error);
alert('Ошибка сохранения настроек: ' + error.message);
}
}
async function toggleMaintenanceMode() {
const isEnabled = document.getElementById('maintenance-mode').checked;
const message = document.getElementById('maintenance-message').value;
const settings = {
maintenanceMode: isEnabled,
maintenanceMessage: message
};
await saveSettings(settings,
isEnabled ? 'Режим обслуживания включен' : 'Режим обслуживания отключен'
);
}
</script>