feat: Реализован полный CRUD для админ-панели и улучшена функциональность

- Portfolio CRUD: добавление, редактирование, удаление, переключение публикации
- Services CRUD: полное управление услугами с возможностью активации/деактивации
- Banner system: новая модель Banner с CRUD операциями и аналитикой кликов
- Telegram integration: расширенные настройки бота, обнаружение чатов, отправка сообщений
- Media management: улучшенная загрузка файлов с оптимизацией изображений и превью
- UI improvements: обновлённые админ-панели с rich-text редактором и drag&drop загрузкой
- Database: добавлена таблица banners с полями для баннеров и аналитики
This commit is contained in:
2025-10-22 20:32:16 +09:00
parent 150891b29d
commit 9477ff6de0
69 changed files with 11451 additions and 2321 deletions

323
views/admin/dashboard.ejs Normal file
View File

@@ -0,0 +1,323 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= 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 bg-blue-100 text-blue-700">
<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 text-gray-600 hover:bg-gray-50 hover:text-gray-900">
<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-tachometer-alt mr-3 text-blue-600"></i>
Панель управления
</h1>
<p class="mt-2 text-gray-600">Обзор основных показателей сайта</p>
</div>
<!-- Stats Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<!-- Portfolio Projects -->
<div class="bg-white overflow-hidden shadow rounded-lg">
<div class="p-5">
<div class="flex items-center">
<div class="flex-shrink-0">
<i class="fas fa-briefcase text-blue-600 text-2xl"></i>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">
Проекты
</dt>
<dd class="text-lg font-medium text-gray-900">
<%= stats.portfolioCount || 0 %>
</dd>
</dl>
</div>
</div>
</div>
<div class="bg-gray-50 px-5 py-3">
<div class="text-sm">
<a href="/admin/portfolio" class="font-medium text-blue-600 hover:text-blue-500">
Посмотреть всё
</a>
</div>
</div>
</div>
<!-- Services -->
<div class="bg-white overflow-hidden shadow rounded-lg">
<div class="p-5">
<div class="flex items-center">
<div class="flex-shrink-0">
<i class="fas fa-cog text-green-600 text-2xl"></i>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">
Услуги
</dt>
<dd class="text-lg font-medium text-gray-900">
<%= stats.servicesCount || 0 %>
</dd>
</dl>
</div>
</div>
</div>
<div class="bg-gray-50 px-5 py-3">
<div class="text-sm">
<a href="/admin/services" class="font-medium text-green-600 hover:text-green-500">
Посмотреть всё
</a>
</div>
</div>
</div>
<!-- Contact Messages -->
<div class="bg-white overflow-hidden shadow rounded-lg">
<div class="p-5">
<div class="flex items-center">
<div class="flex-shrink-0">
<i class="fas fa-envelope text-purple-600 text-2xl"></i>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">
Сообщения
</dt>
<dd class="text-lg font-medium text-gray-900">
<%= stats.contactsCount || 0 %>
</dd>
</dl>
</div>
</div>
</div>
<div class="bg-gray-50 px-5 py-3">
<div class="text-sm">
<a href="/admin/contacts" class="font-medium text-purple-600 hover:text-purple-500">
Посмотреть всё
</a>
</div>
</div>
</div>
<!-- Users -->
<div class="bg-white overflow-hidden shadow rounded-lg">
<div class="p-5">
<div class="flex items-center">
<div class="flex-shrink-0">
<i class="fas fa-users text-orange-600 text-2xl"></i>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">
Пользователи
</dt>
<dd class="text-lg font-medium text-gray-900">
<%= stats.usersCount || 0 %>
</dd>
</dl>
</div>
</div>
</div>
<div class="bg-gray-50 px-5 py-3">
<div class="text-sm">
<a href="/admin/users" class="font-medium text-orange-600 hover:text-orange-500">
Посмотреть всё
</a>
</div>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Recent Portfolio Projects -->
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">
Последние проекты
</h3>
</div>
<div class="p-6">
<% if (recentPortfolio && recentPortfolio.length > 0) { %>
<div class="space-y-4">
<% recentPortfolio.forEach(function(project) { %>
<div class="flex items-center space-x-4">
<div class="flex-shrink-0">
<i class="fas fa-briefcase text-blue-600"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">
<%= project.title %>
</p>
<p class="text-sm text-gray-500">
<%= project.category %>
</p>
</div>
<div class="flex-shrink-0">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
<%= project.status %>
</span>
</div>
</div>
<% }); %>
</div>
<% } else { %>
<p class="text-gray-500 text-sm">Нет недавних проектов</p>
<% } %>
</div>
</div>
<!-- Recent Contact Messages -->
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">
Последние сообщения
</h3>
</div>
<div class="p-6">
<% if (recentContacts && recentContacts.length > 0) { %>
<div class="space-y-4">
<% recentContacts.forEach(function(contact) { %>
<div class="flex items-center space-x-4">
<div class="flex-shrink-0">
<i class="fas fa-envelope text-purple-600"></i>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">
<%= contact.name %>
</p>
<p class="text-sm text-gray-500 truncate">
<%= contact.email %>
</p>
</div>
<div class="flex-shrink-0">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
<%= contact.status %>
</span>
</div>
</div>
<% }); %>
</div>
<% } else { %>
<p class="text-gray-500 text-sm">Нет недавних сообщений</p>
<% } %>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-medium text-gray-900 mb-4">
Быстрые действия
</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<a href="/admin/portfolio/new"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700">
<i class="fas fa-plus mr-2"></i>
Добавить проект
</a>
<a href="/admin/services/new"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700">
<i class="fas fa-plus mr-2"></i>
Добавить услугу
</a>
<a href="/admin/settings"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-gray-600 hover:bg-gray-700">
<i class="fas fa-cogs mr-2"></i>
Настройки сайта
</a>
</div>
</div>
</div>
</main>
</div>
<!-- JavaScript -->
<script src="/js/main.js"></script>
</body>
</html>