360 lines
16 KiB
Plaintext
360 lines
16 KiB
Plaintext
<!-- 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="fab fa-telegram mr-2 text-info"></i>Telegram Bot</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">Telegram Bot</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Main content -->
|
||
<section class="content">
|
||
<div class="container-fluid">
|
||
<!-- Bot Status Card -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3 class="card-title">Статус бота</h3>
|
||
<div class="card-tools">
|
||
<button id="refresh-status" class="btn btn-sm btn-default">
|
||
<i class="fas fa-sync-alt"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="info-box">
|
||
<span class="info-box-icon" id="status-icon">
|
||
<i class="fas fa-question"></i>
|
||
</span>
|
||
<div class="info-box-content">
|
||
<span class="info-box-text">Статус подключения</span>
|
||
<span class="info-box-number" id="status-text">Проверка...</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="info-box">
|
||
<span class="info-box-icon bg-info">
|
||
<i class="fab fa-telegram"></i>
|
||
</span>
|
||
<div class="info-box-content">
|
||
<span class="info-box-text">Имя бота</span>
|
||
<span class="info-box-number" id="bot-name">Загрузка...</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Configuration Card -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3 class="card-title">Конфигурация</h3>
|
||
</div>
|
||
<form id="config-form">
|
||
<div class="card-body">
|
||
<div class="form-group">
|
||
<label for="bot-token">Токен бота</label>
|
||
<div class="input-group">
|
||
<input type="password" class="form-control" id="bot-token" name="botToken" placeholder="Введите токен бота">
|
||
<div class="input-group-append">
|
||
<button type="button" class="btn btn-outline-secondary" onclick="toggleTokenVisibility()">
|
||
<i class="fas fa-eye" id="token-eye"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<small class="form-text text-muted">
|
||
Получите токен у <a href="https://t.me/BotFather" target="_blank">@BotFather</a>
|
||
</small>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="admin-chat-id">ID чата администратора</label>
|
||
<input type="text" class="form-control" id="admin-chat-id" name="adminChatId" placeholder="Введите ID чата">
|
||
<small class="form-text text-muted">
|
||
Узнайте ваш ID чата у <a href="https://t.me/userinfobot" target="_blank">@userinfobot</a>
|
||
</small>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="custom-control custom-switch">
|
||
<input type="checkbox" class="custom-control-input" id="notifications-enabled" name="notificationsEnabled">
|
||
<label class="custom-control-label" for="notifications-enabled">Включить уведомления</label>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Типы уведомлений</label>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="custom-control custom-checkbox">
|
||
<input type="checkbox" class="custom-control-input" id="notify-contacts" name="notifyContacts">
|
||
<label class="custom-control-label" for="notify-contacts">Новые контакты</label>
|
||
</div>
|
||
<div class="custom-control custom-checkbox">
|
||
<input type="checkbox" class="custom-control-input" id="notify-orders" name="notifyOrders">
|
||
<label class="custom-control-label" for="notify-orders">Новые заказы</label>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="custom-control custom-checkbox">
|
||
<input type="checkbox" class="custom-control-input" id="notify-errors" name="notifyErrors">
|
||
<label class="custom-control-label" for="notify-errors">Системные ошибки</label>
|
||
</div>
|
||
<div class="custom-control custom-checkbox">
|
||
<input type="checkbox" class="custom-control-input" id="notify-updates" name="notifyUpdates">
|
||
<label class="custom-control-label" for="notify-updates">Обновления системы</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-footer">
|
||
<button type="submit" class="btn btn-primary">
|
||
<i class="fas fa-save mr-1"></i>Сохранить
|
||
</button>
|
||
<button type="button" class="btn btn-secondary ml-2" onclick="testConnection()">
|
||
<i class="fas fa-bolt mr-1"></i>Проверить подключение
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Test Message Card -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h3 class="card-title">Тестовое сообщение</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="form-group">
|
||
<label for="test-message">Сообщение</label>
|
||
<textarea class="form-control" id="test-message" rows="3" placeholder="Введите тестовое сообщение...">Тестовое сообщение от SmartSolTech Admin Panel</textarea>
|
||
</div>
|
||
<button type="button" class="btn btn-info" onclick="sendTestMessage()">
|
||
<i class="fas fa-paper-plane mr-1"></i>Отправить тест
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Activity Log 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="clearLog()">
|
||
<i class="fas fa-trash"></i> Очистить
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div id="activity-log" style="max-height: 300px; overflow-y: auto;">
|
||
<!-- Log entries will be added here -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<script>
|
||
let activityLog = [];
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
loadConfig();
|
||
checkBotStatus();
|
||
initializeLog();
|
||
|
||
document.getElementById('config-form').addEventListener('submit', saveConfig);
|
||
});
|
||
|
||
function addLog(message, type = 'info') {
|
||
const timestamp = new Date().toLocaleString('ru-RU');
|
||
const logEntry = { timestamp, message, type };
|
||
|
||
activityLog.unshift(logEntry);
|
||
if (activityLog.length > 100) {
|
||
activityLog = activityLog.slice(0, 100);
|
||
}
|
||
|
||
updateLogDisplay();
|
||
}
|
||
|
||
function updateLogDisplay() {
|
||
const logContainer = document.getElementById('activity-log');
|
||
const typeColors = {
|
||
info: 'text-info',
|
||
success: 'text-success',
|
||
error: 'text-danger',
|
||
warning: 'text-warning'
|
||
};
|
||
|
||
logContainer.innerHTML = activityLog.map(entry => `
|
||
<div class="mb-2">
|
||
<small class="text-muted">[${entry.timestamp}]</small>
|
||
<span class="${typeColors[entry.type] || 'text-info'}">${entry.message}</span>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
function initializeLog() {
|
||
addLog('Telegram Bot панель загружена');
|
||
}
|
||
|
||
function clearLog() {
|
||
if (confirm('Очистить журнал активности?')) {
|
||
activityLog = [];
|
||
updateLogDisplay();
|
||
addLog('Журнал активности очищен');
|
||
}
|
||
}
|
||
|
||
async function loadConfig() {
|
||
try {
|
||
const response = await fetch('/api/admin/telegram/config');
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
const config = data.config;
|
||
document.getElementById('bot-token').value = config.botToken || '';
|
||
document.getElementById('admin-chat-id').value = config.adminChatId || '';
|
||
document.getElementById('notifications-enabled').checked = config.notificationsEnabled || false;
|
||
document.getElementById('notify-contacts').checked = config.notifyContacts || false;
|
||
document.getElementById('notify-orders').checked = config.notifyOrders || false;
|
||
document.getElementById('notify-errors').checked = config.notifyErrors || false;
|
||
document.getElementById('notify-updates').checked = config.notifyUpdates || false;
|
||
|
||
addLog('Конфигурация загружена');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error loading config:', error);
|
||
addLog('Ошибка загрузки конфигурации: ' + error.message, 'error');
|
||
}
|
||
}
|
||
|
||
async function saveConfig(event) {
|
||
event.preventDefault();
|
||
|
||
const formData = new FormData(event.target);
|
||
const config = {
|
||
botToken: formData.get('botToken'),
|
||
adminChatId: formData.get('adminChatId'),
|
||
notificationsEnabled: formData.has('notificationsEnabled'),
|
||
notifyContacts: formData.has('notifyContacts'),
|
||
notifyOrders: formData.has('notifyOrders'),
|
||
notifyErrors: formData.has('notifyErrors'),
|
||
notifyUpdates: formData.has('notifyUpdates')
|
||
};
|
||
|
||
try {
|
||
const response = await fetch('/api/admin/telegram/config', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(config)
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
addLog('Конфигурация сохранена', 'success');
|
||
setTimeout(checkBotStatus, 1000);
|
||
} else {
|
||
throw new Error(data.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error saving config:', error);
|
||
addLog('Ошибка сохранения конфигурации: ' + error.message, 'error');
|
||
}
|
||
}
|
||
|
||
async function checkBotStatus() {
|
||
try {
|
||
const response = await fetch('/api/admin/telegram/status');
|
||
const data = await response.json();
|
||
|
||
const statusIcon = document.getElementById('status-icon');
|
||
const statusText = document.getElementById('status-text');
|
||
const botName = document.getElementById('bot-name');
|
||
|
||
if (data.success && data.status.connected) {
|
||
statusIcon.className = 'info-box-icon bg-success';
|
||
statusIcon.innerHTML = '<i class="fas fa-check"></i>';
|
||
statusText.textContent = 'Подключен';
|
||
botName.textContent = data.status.botInfo.first_name;
|
||
addLog('Бот подключен: ' + data.status.botInfo.first_name, 'success');
|
||
} else {
|
||
statusIcon.className = 'info-box-icon bg-danger';
|
||
statusIcon.innerHTML = '<i class="fas fa-times"></i>';
|
||
statusText.textContent = 'Не подключен';
|
||
botName.textContent = 'Не подключен';
|
||
addLog('Бот не подключен: ' + (data.message || 'Неизвестная ошибка'), 'error');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error checking bot status:', error);
|
||
const statusIcon = document.getElementById('status-icon');
|
||
const statusText = document.getElementById('status-text');
|
||
const botName = document.getElementById('bot-name');
|
||
|
||
statusIcon.className = 'info-box-icon bg-warning';
|
||
statusIcon.innerHTML = '<i class="fas fa-exclamation"></i>';
|
||
statusText.textContent = 'Ошибка проверки';
|
||
botName.textContent = 'Ошибка';
|
||
addLog('Ошибка проверки статуса: ' + error.message, 'error');
|
||
}
|
||
}
|
||
|
||
async function testConnection() {
|
||
addLog('Проверка подключения...');
|
||
await checkBotStatus();
|
||
}
|
||
|
||
async function sendTestMessage() {
|
||
const message = document.getElementById('test-message').value;
|
||
if (!message.trim()) {
|
||
alert('Введите сообщение для отправки');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
addLog('Отправка тестового сообщения...');
|
||
|
||
const response = await fetch('/api/admin/telegram/test', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ message })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
addLog('Тестовое сообщение отправлено', 'success');
|
||
} else {
|
||
throw new Error(data.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error sending test message:', error);
|
||
addLog('Ошибка отправки сообщения: ' + error.message, 'error');
|
||
}
|
||
}
|
||
|
||
function toggleTokenVisibility() {
|
||
const tokenInput = document.getElementById('bot-token');
|
||
const tokenEye = document.getElementById('token-eye');
|
||
|
||
if (tokenInput.type === 'password') {
|
||
tokenInput.type = 'text';
|
||
tokenEye.className = 'fas fa-eye-slash';
|
||
} else {
|
||
tokenInput.type = 'password';
|
||
tokenEye.className = 'fas fa-eye';
|
||
}
|
||
}
|
||
</script> |