Files
sst_site/views/admin/telegram.ejs
Andrey K. Choi 9477ff6de0 feat: Реализован полный CRUD для админ-панели и улучшена функциональность
- Portfolio CRUD: добавление, редактирование, удаление, переключение публикации
- Services CRUD: полное управление услугами с возможностью активации/деактивации
- Banner system: новая модель Banner с CRUD операциями и аналитикой кликов
- Telegram integration: расширенные настройки бота, обнаружение чатов, отправка сообщений
- Media management: улучшенная загрузка файлов с оптимизацией изображений и превью
- UI improvements: обновлённые админ-панели с rich-text редактором и drag&drop загрузкой
- Database: добавлена таблица banners с полями для баннеров и аналитики
2025-10-22 20:32:16 +09:00

885 lines
47 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Telegram Bot - 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 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 bg-blue-100 text-blue-700">
<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">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-gray-900 flex items-center">
<i class="fab fa-telegram mr-3 text-blue-500"></i>
Telegram Bot
</h1>
<p class="mt-2 text-gray-600">Настройка и управление уведомлениями через Telegram</p>
</div>
<div class="flex items-center space-x-3">
<div class="flex items-center">
<div class="w-3 h-3 rounded-full <%= botConfigured ? 'bg-green-500' : 'bg-red-500' %> mr-2"></div>
<span class="text-sm font-medium <%= botConfigured ? 'text-green-700' : 'text-red-700' %>">
<%= botConfigured ? 'Подключен' : 'Не настроен' %>
</span>
</div>
</div>
</div>
</div>
<!-- Bot Configuration -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">
<i class="fas fa-cog mr-2 text-blue-500"></i>
Конфигурация бота
</h3>
<form id="bot-config-form" class="space-y-6">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Bot Token -->
<div>
<label for="botToken" class="block text-sm font-medium text-gray-700 mb-2">
Токен бота *
</label>
<div class="relative">
<input type="password" id="botToken" name="botToken"
value="<%= botToken %>"
placeholder="1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZ"
class="block w-full pr-10 border border-gray-300 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<button type="button" onclick="toggleTokenVisibility()"
class="absolute inset-y-0 right-0 pr-3 flex items-center">
<i id="token-eye" class="fas fa-eye text-gray-400"></i>
</button>
</div>
<p class="mt-1 text-sm text-gray-500">
Получите токен от <a href="https://t.me/BotFather" target="_blank" class="text-blue-600 underline">@BotFather</a>
</p>
</div>
<!-- Default Chat ID -->
<div>
<label for="chatId" class="block text-sm font-medium text-gray-700 mb-2">
ID чата по умолчанию
</label>
<input type="text" id="chatId" name="chatId"
value="<%= chatId %>"
placeholder="-1001234567890"
class="block w-full border border-gray-300 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<p class="mt-1 text-sm text-gray-500">
Оставьте пустым, если будете выбирать чат из списка
</p>
</div>
</div>
<div class="flex space-x-3">
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-save mr-2"></i>
Сохранить настройки
</button>
<button type="button" onclick="getBotInfo()" class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-info-circle mr-2"></i>
Получить информацию о боте
</button>
</div>
</form>
<div id="config-result" class="mt-4 hidden"></div>
</div>
<% if (botConfigured) { %>
<!-- Bot Information -->
<div class="bg-white shadow rounded-lg p-6">
<div class="flex items-center justify-between mb-6">
<h3 class="text-lg font-semibold text-gray-900">
<i class="fas fa-robot mr-2 text-green-500"></i>
Информация о боте
</h3>
<button onclick="refreshBotInfo()" class="text-blue-600 hover:text-blue-800 text-sm">
<i class="fas fa-refresh mr-1"></i>
Обновить
</button>
</div>
<div id="bot-info-container">
<% if (botInfo) { %>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">Имя бота</div>
<div class="text-lg font-semibold text-gray-900">@<%= botInfo.username %></div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">Отображаемое имя</div>
<div class="text-lg font-semibold text-gray-900"><%= botInfo.first_name %></div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">ID бота</div>
<div class="text-lg font-semibold text-gray-900"><%= botInfo.id %></div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">Может читать сообщения</div>
<div class="text-lg font-semibold <%= botInfo.can_read_all_group_messages ? 'text-green-600' : 'text-red-600' %>">
<%= botInfo.can_read_all_group_messages ? 'Да' : 'Нет' %>
</div>
</div>
</div>
<% } else { %>
<div class="text-center py-4 text-gray-500">
<i class="fas fa-robot text-4xl text-gray-300 mb-2"></i>
<p>Настройте токен бота для получения информации</p>
</div>
<% } %>
</div>
</div>
<!-- Available Chats -->
<div class="bg-white shadow rounded-lg p-6">
<div class="flex items-center justify-between mb-6">
<h3 class="text-lg font-semibold text-gray-900">
<i class="fas fa-comments mr-2 text-blue-500"></i>
Доступные чаты
</h3>
<button onclick="discoverChats()" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded text-sm transition-colors">
<i class="fas fa-search mr-1"></i>
Найти чаты
</button>
</div>
<div id="available-chats-container">
<% if (availableChats && availableChats.length > 0) { %>
<div class="grid gap-3">
<% availableChats.forEach(chat => { %>
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
<i class="fas <%= chat.type === 'group' || chat.type === 'supergroup' ? 'fa-users' : 'fa-user' %> text-blue-600 text-sm"></i>
</div>
<div>
<div class="font-medium text-gray-900"><%= chat.title %></div>
<div class="text-sm text-gray-500">
<%= chat.type %> • ID: <%= chat.id %>
<% if (chat.username) { %>• @<%= chat.username %><% } %>
</div>
</div>
</div>
<button onclick="selectChat('<%= chat.id %>', '<%= chat.title %>')"
class="text-blue-600 hover:text-blue-800 text-sm">
Выбрать
</button>
</div>
<% }); %>
</div>
<% } else { %>
<div class="text-center py-8 text-gray-500">
<i class="fas fa-comments text-4xl text-gray-300 mb-4"></i>
<p class="mb-2">Чаты не найдены</p>
<p class="text-sm">Отправьте боту сообщение или добавьте его в группу, затем нажмите "Найти чаты"</p>
</div>
<% } %>
</div>
</div>
<% } %>
<!-- Message Sender -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">
<i class="fas fa-paper-plane mr-2 text-purple-500"></i>
Отправить сообщение
</h3>
<form id="send-message-form" class="space-y-6">
<!-- Message Content -->
<div>
<label for="messageText" class="block text-sm font-medium text-gray-700 mb-2">
Текст сообщения *
</label>
<textarea id="messageText" name="message" rows="4" required
placeholder="Введите сообщение..."
class="block w-full border border-gray-300 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"></textarea>
</div>
<!-- Recipients -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">
Получатели
</label>
<div id="recipients-container" class="space-y-2">
<% if (availableChats && availableChats.length > 0) { %>
<% availableChats.forEach(chat => { %>
<label class="flex items-center">
<input type="checkbox" name="chatIds" value="<%= chat.id %>"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<span class="ml-2 text-sm text-gray-900">
<%= chat.title %>
<span class="text-gray-500">(<%= chat.type %>)</span>
</span>
</label>
<% }); %>
<% } else { %>
<div class="text-sm text-gray-500">
<i class="fas fa-info-circle mr-1"></i>
Сообщение будет отправлено в чат по умолчанию
</div>
<% } %>
</div>
</div>
<!-- Message Options -->
<div class="bg-gray-50 p-4 rounded-lg">
<h4 class="text-sm font-medium text-gray-900 mb-3">Настройки сообщения</h4>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<label class="flex items-center">
<input type="checkbox" name="disableWebPagePreview"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<span class="ml-2 text-sm text-gray-900">Отключить предпросмотр ссылок</span>
</label>
<label class="flex items-center">
<input type="checkbox" name="disableNotification"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<span class="ml-2 text-sm text-gray-900">Тихое уведомление</span>
</label>
</div>
<div class="mt-4">
<label for="parseMode" class="block text-sm font-medium text-gray-700 mb-1">
Формат текста
</label>
<select name="parseMode" id="parseMode"
class="block w-full border border-gray-300 rounded-md px-3 py-2 text-sm">
<option value="HTML">HTML</option>
<option value="Markdown">Markdown</option>
<option value="">Обычный текст</option>
</select>
</div>
</div>
<!-- Submit Buttons -->
<div class="flex justify-between">
<button type="button" onclick="previewMessage()"
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
<i class="fas fa-eye mr-2"></i>
Предпросмотр
</button>
<div class="space-x-3">
<button type="button" onclick="testConnection()"
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
<i class="fas fa-vial mr-2"></i>
Тест соединения
</button>
<button type="submit" id="sendMessageBtn"
class="inline-flex items-center px-6 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700">
<i class="fas fa-paper-plane mr-2"></i>
Отправить сообщение
</button>
</div>
</div>
</form>
<div id="send-result" class="mt-4 hidden"></div>
</div>
<!-- Bot Status and Controls -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Connection Test -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">
<i class="fas fa-plug mr-2 text-green-500"></i>
Проверка подключения
</h3>
<p class="text-gray-600 mb-4">
Отправить тестовое сообщение для проверки работоспособности бота.
</p>
<button id="test-connection" class="w-full bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-vial mr-2"></i>
Тестировать подключение
</button>
<div id="test-result" class="mt-4 hidden"></div>
</div>
<!-- Send Custom Message -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">
<i class="fas fa-paper-plane mr-2 text-blue-500"></i>
Отправить сообщение
</h3>
<form id="send-message-form">
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">
Сообщение
</label>
<textarea
id="custom-message"
rows="4"
class="w-full border border-gray-300 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Введите текст сообщения..."></textarea>
</div>
<button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors">
<i class="fas fa-send mr-2"></i>
Отправить
</button>
</form>
<div id="send-result" class="mt-4 hidden"></div>
</div>
</div>
<!-- Notification Settings -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">
<i class="fas fa-bell mr-2 text-purple-500"></i>
Настройки уведомлений
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Notification Types -->
<div>
<h4 class="font-medium text-gray-900 mb-4">Типы уведомлений</h4>
<div class="space-y-3">
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center">
<i class="fas fa-envelope mr-3 text-blue-500"></i>
<span class="text-sm text-gray-900">Новые обращения</span>
</div>
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
</div>
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center">
<i class="fas fa-calculator mr-3 text-green-500"></i>
<span class="text-sm text-gray-900">Расчеты стоимости</span>
</div>
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
</div>
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center">
<i class="fas fa-briefcase mr-3 text-purple-500"></i>
<span class="text-sm text-gray-900">Новые проекты</span>
</div>
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
</div>
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center">
<i class="fas fa-cog mr-3 text-orange-500"></i>
<span class="text-sm text-gray-900">Новые услуги</span>
</div>
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
</div>
</div>
</div>
<!-- Bot Information -->
<div>
<h4 class="font-medium text-gray-900 mb-4">Информация о боте</h4>
<div class="space-y-3">
<div class="flex justify-between">
<span class="text-sm text-gray-600">Статус:</span>
<span class="text-sm font-medium text-green-600">Активен</span>
</div>
<div class="flex justify-between">
<span class="text-sm text-gray-600">Токен:</span>
<span class="text-sm font-mono text-gray-800">••••••••••</span>
</div>
<div class="flex justify-between">
<span class="text-sm text-gray-600">Chat ID:</span>
<span class="text-sm font-mono text-gray-800">••••••••••</span>
</div>
<div class="flex justify-between">
<span class="text-sm text-gray-600">Последнее уведомление:</span>
<span class="text-sm text-gray-600">Недавно</span>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Notifications -->
<div class="bg-white shadow rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-6">
<i class="fas fa-history mr-2 text-gray-500"></i>
Недавние уведомления
</h3>
<div class="text-center py-8 text-gray-500">
<i class="fas fa-inbox text-4xl text-gray-300 mb-4"></i>
<p>Уведомления будут отображаться здесь после отправки</p>
</div>
</div>
<% } %>
</div>
</main>
</div>
<!-- JavaScript -->
<script src="/js/main.js"></script>
<script>
// Bot Configuration
document.getElementById('bot-config-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
try {
showLoading('Сохранение настроек...');
const response = await fetch('/admin/telegram/configure', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showResult('config-result', result.message, 'success');
// Update bot info if available
if (result.botInfo) {
updateBotInfo(result.botInfo);
}
if (result.availableChats) {
updateAvailableChats(result.availableChats);
}
} else {
showResult('config-result', result.message, 'error');
}
} catch (error) {
showResult('config-result', 'Ошибка при сохранении настроек', 'error');
} finally {
hideLoading();
}
});
// Send message form
document.getElementById('send-message-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const message = formData.get('message');
const chatIds = formData.getAll('chatIds');
const parseMode = formData.get('parseMode');
const disableWebPagePreview = formData.has('disableWebPagePreview');
const disableNotification = formData.has('disableNotification');
if (!message.trim()) {
showResult('send-result', 'Введите текст сообщения', 'error');
return;
}
const data = {
message: message.trim(),
chatIds: chatIds.length > 0 ? chatIds : [],
parseMode,
disableWebPagePreview,
disableNotification
};
try {
const btn = document.getElementById('sendMessageBtn');
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Отправка...';
const response = await fetch('/admin/telegram/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showResult('send-result', result.message, 'success');
document.getElementById('messageText').value = '';
} else {
showResult('send-result', result.message, 'error');
}
} catch (error) {
showResult('send-result', 'Ошибка при отправке сообщения', 'error');
} finally {
const btn = document.getElementById('sendMessageBtn');
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-paper-plane mr-2"></i>Отправить сообщение';
}
});
// Utility functions
function toggleTokenVisibility() {
const input = document.getElementById('botToken');
const eye = document.getElementById('token-eye');
if (input.type === 'password') {
input.type = 'text';
eye.className = 'fas fa-eye-slash text-gray-400';
} else {
input.type = 'password';
eye.className = 'fas fa-eye text-gray-400';
}
}
async function getBotInfo() {
try {
showLoading('Получение информации о боте...');
const response = await fetch('/admin/telegram/info');
const result = await response.json();
if (result.success) {
updateBotInfo(result.botInfo);
updateAvailableChats(result.availableChats);
showResult('config-result', 'Информация о боте обновлена', 'success');
} else {
showResult('config-result', result.message, 'error');
}
} catch (error) {
showResult('config-result', 'Ошибка при получении информации о боте', 'error');
} finally {
hideLoading();
}
}
async function refreshBotInfo() {
await getBotInfo();
}
async function discoverChats() {
try {
showLoading('Поиск доступных чатов...');
const response = await fetch('/admin/telegram/info');
const result = await response.json();
if (result.success && result.availableChats) {
updateAvailableChats(result.availableChats);
showNotification('Найдено чатов: ' + result.availableChats.length, 'success');
} else {
showNotification('Чаты не найдены', 'warning');
}
} catch (error) {
showNotification('Ошибка при поиске чатов', 'error');
} finally {
hideLoading();
}
}
function selectChat(chatId, chatTitle) {
document.getElementById('chatId').value = chatId;
showNotification(`Выбран чат: ${chatTitle}`, 'success');
}
async function testConnection() {
try {
showLoading('Тестирование соединения...');
const response = await fetch('/admin/telegram/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
showResult('send-result', 'Соединение успешно! Тестовое сообщение отправлено.', 'success');
} else {
showResult('send-result', result.message, 'error');
}
} catch (error) {
showResult('send-result', 'Ошибка при тестировании соединения', 'error');
} finally {
hideLoading();
}
}
function previewMessage() {
const message = document.getElementById('messageText').value;
const parseMode = document.getElementById('parseMode').value;
if (!message.trim()) {
showNotification('Введите текст сообщения для предпросмотра', 'warning');
return;
}
// Simple preview modal (you can enhance this)
const preview = window.open('', 'preview', 'width=400,height=300');
preview.document.write(`
<html>
<head><title>Предпросмотр сообщения</title></head>
<body style="font-family: Arial, sans-serif; padding: 20px;">
<h3>Предпросмотр сообщения (${parseMode || 'Обычный текст'})</h3>
<div style="border: 1px solid #ccc; padding: 10px; background: #f9f9f9;">
${parseMode === 'HTML' ? message : message.replace(/\n/g, '<br>')}
</div>
<button onclick="window.close()" style="margin-top: 10px;">Закрыть</button>
</body>
</html>
`);
}
// UI Helper functions
function updateBotInfo(botInfo) {
const container = document.getElementById('bot-info-container');
if (!botInfo) return;
container.innerHTML = `
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">Имя бота</div>
<div class="text-lg font-semibold text-gray-900">@${botInfo.username}</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">Отображаемое имя</div>
<div class="text-lg font-semibold text-gray-900">${botInfo.first_name}</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">ID бота</div>
<div class="text-lg font-semibold text-gray-900">${botInfo.id}</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<div class="text-sm text-gray-600">Может читать сообщения</div>
<div class="text-lg font-semibold ${botInfo.can_read_all_group_messages ? 'text-green-600' : 'text-red-600'}">
${botInfo.can_read_all_group_messages ? 'Да' : 'Нет'}
</div>
</div>
</div>
`;
}
function updateAvailableChats(chats) {
const container = document.getElementById('available-chats-container');
if (!chats || chats.length === 0) {
container.innerHTML = `
<div class="text-center py-8 text-gray-500">
<i class="fas fa-comments text-4xl text-gray-300 mb-4"></i>
<p class="mb-2">Чаты не найдены</p>
<p class="text-sm">Отправьте боту сообщение или добавьте его в группу, затем нажмите "Найти чаты"</p>
</div>
`;
return;
}
const chatsHtml = chats.map(chat => `
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
<i class="fas ${chat.type === 'group' || chat.type === 'supergroup' ? 'fa-users' : 'fa-user'} text-blue-600 text-sm"></i>
</div>
<div>
<div class="font-medium text-gray-900">${chat.title}</div>
<div class="text-sm text-gray-500">
${chat.type} • ID: ${chat.id}
${chat.username ? '• @' + chat.username : ''}
</div>
</div>
</div>
<button onclick="selectChat('${chat.id}', '${chat.title}')"
class="text-blue-600 hover:text-blue-800 text-sm">
Выбрать
</button>
</div>
`).join('');
container.innerHTML = `<div class="grid gap-3">${chatsHtml}</div>`;
// Also update recipients list
updateRecipientsList(chats);
}
function updateRecipientsList(chats) {
const container = document.getElementById('recipients-container');
if (!chats || chats.length === 0) {
container.innerHTML = `
<div class="text-sm text-gray-500">
<i class="fas fa-info-circle mr-1"></i>
Сообщение будет отправлено в чат по умолчанию
</div>
`;
return;
}
const recipientsHtml = chats.map(chat => `
<label class="flex items-center">
<input type="checkbox" name="chatIds" value="${chat.id}"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<span class="ml-2 text-sm text-gray-900">
${chat.title}
<span class="text-gray-500">(${chat.type})</span>
</span>
</label>
`).join('');
container.innerHTML = recipientsHtml;
}
function showResult(elementId, message, type) {
const element = document.getElementById(elementId);
const className = type === 'success' ? 'bg-green-100 text-green-800' :
type === 'warning' ? 'bg-yellow-100 text-yellow-800' :
'bg-red-100 text-red-800';
const icon = type === 'success' ? 'fa-check' :
type === 'warning' ? 'fa-exclamation-triangle' :
'fa-times';
element.className = `mt-4 p-3 rounded-lg ${className}`;
element.innerHTML = `<i class="fas ${icon} mr-2"></i>${message}`;
element.classList.remove('hidden');
setTimeout(() => {
element.classList.add('hidden');
}, 5000);
}
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `fixed top-4 right-4 z-50 px-4 py-3 rounded-lg shadow-lg text-white max-w-sm transform transition-all duration-300 translate-x-full`;
switch(type) {
case 'success':
notification.classList.add('bg-green-600');
break;
case 'error':
notification.classList.add('bg-red-600');
break;
case 'warning':
notification.classList.add('bg-yellow-600');
break;
default:
notification.classList.add('bg-blue-600');
}
notification.innerHTML = `
<div class="flex items-center">
<i class="fas ${type === 'success' ? 'fa-check-circle' : type === 'error' ? 'fa-exclamation-circle' : type === 'warning' ? 'fa-exclamation-triangle' : 'fa-info-circle'} mr-2"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.classList.remove('translate-x-full');
}, 100);
setTimeout(() => {
notification.classList.add('translate-x-full');
setTimeout(() => {
if (document.body.contains(notification)) {
document.body.removeChild(notification);
}
}, 300);
}, 4000);
}
function showLoading(message) {
// Create or show loading overlay
let overlay = document.getElementById('loading-overlay');
if (!overlay) {
overlay = document.createElement('div');
overlay.id = 'loading-overlay';
overlay.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';
overlay.innerHTML = `
<div class="bg-white p-6 rounded-lg shadow-lg">
<div class="flex items-center">
<i class="fas fa-spinner fa-spin text-blue-600 text-xl mr-3"></i>
<span id="loading-message">${message}</span>
</div>
</div>
`;
document.body.appendChild(overlay);
} else {
document.getElementById('loading-message').textContent = message;
overlay.style.display = 'flex';
}
}
function hideLoading() {
const overlay = document.getElementById('loading-overlay');
if (overlay) {
overlay.style.display = 'none';
}
}
</script>
</body>
</html>