Files
crm.clientright.ru/crm_extensions/file_storage/test_redis_final.html
Fedor 9245768987 🚀 CRM Files Migration & Real-time Features
 Features:
- Migrated ALL files to new S3 structure (Projects, Contacts, Accounts, HelpDesk, Invoice, etc.)
- Added Nextcloud folder buttons to ALL modules
- Fixed Nextcloud editor integration
- WebSocket server for real-time updates
- Redis Pub/Sub integration
- File path manager for organized storage
- Redis caching for performance (Functions.php)

📁 New Structure:
Documents/Project/ProjectName_ID/file_docID.ext
Documents/Contacts/FirstName_LastName_ID/file_docID.ext
Documents/Accounts/AccountName_ID/file_docID.ext

🔧 Technical:
- FilePathManager for standardized paths
- S3StorageService integration
- WebSocket server (Node.js + Docker)
- Redis cache for getBasicModuleInfo()
- Predis library for Redis connectivity

📝 Scripts:
- Migration scripts for all modules
- Test pages for WebSocket/SSE/Polling
- Documentation (MIGRATION_*.md, REDIS_*.md)

🎯 Result: 15,000+ files migrated successfully!
2025-10-24 19:59:28 +03:00

295 lines
9.5 KiB
HTML
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>🔴 Redis SSE - Финальный тест</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 20px auto;
padding: 20px;
background: #f5f5f5;
}
.container {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #2c3e50;
margin-bottom: 30px;
}
.status {
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
font-weight: bold;
}
.status.connected {
background: #d4edda;
border: 2px solid #28a745;
color: #155724;
}
.status.disconnected {
background: #f8d7da;
border: 2px solid #dc3545;
color: #721c24;
}
.status.connecting {
background: #fff3cd;
border: 2px solid #ffc107;
color: #856404;
}
.controls {
margin: 20px 0;
display: flex;
gap: 10px;
}
button {
padding: 12px 24px;
font-size: 16px;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
button.primary {
background: #007bff;
color: white;
}
button.primary:hover {
background: #0056b3;
}
button.success {
background: #28a745;
color: white;
}
button.success:hover {
background: #1e7e34;
}
button.danger {
background: #dc3545;
color: white;
}
button.danger:hover {
background: #c82333;
}
.events {
margin-top: 30px;
}
.event {
padding: 15px;
margin: 10px 0;
border-radius: 6px;
border-left: 4px solid;
background: #f8f9fa;
}
.event.test {
border-left-color: #17a2b8;
}
.event.file_created {
border-left-color: #28a745;
}
.event.file_updated {
border-left-color: #ffc107;
}
.event.file_deleted {
border-left-color: #dc3545;
}
.event.connected {
border-left-color: #007bff;
}
.event.heartbeat {
border-left-color: #6c757d;
opacity: 0.6;
}
.event .time {
color: #6c757d;
font-size: 12px;
float: right;
}
.event .type {
font-weight: bold;
margin-bottom: 8px;
}
.event .data {
font-family: 'Courier New', monospace;
background: white;
padding: 10px;
border-radius: 4px;
font-size: 13px;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin: 20px 0;
}
.stat-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 8px;
text-align: center;
}
.stat-value {
font-size: 32px;
font-weight: bold;
}
.stat-label {
font-size: 14px;
opacity: 0.9;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>🔴 Redis SSE - Финальный тест</h1>
<div id="status" class="status connecting">
🔄 Подключение к Redis SSE...
</div>
<div class="stats">
<div class="stat-card">
<div class="stat-value" id="totalEvents">0</div>
<div class="stat-label">Всего событий</div>
</div>
<div class="stat-card">
<div class="stat-value" id="lastEventTime">-</div>
<div class="stat-label">Последнее событие</div>
</div>
<div class="stat-card">
<div class="stat-value" id="connectionTime">0s</div>
<div class="stat-label">Время подключения</div>
</div>
</div>
<div class="controls">
<button class="primary" onclick="reconnect()">🔄 Переподключиться</button>
<button class="success" onclick="sendTestEvent()">🧪 Тест события</button>
<button class="danger" onclick="clearEvents()">🗑️ Очистить</button>
</div>
<div class="events">
<h3>📋 События:</h3>
<div id="events"></div>
</div>
</div>
<script>
let eventSource = null;
let totalEvents = 0;
let connectionStart = Date.now();
let connectionTimer = null;
function connect() {
const statusEl = document.getElementById('status');
statusEl.className = 'status connecting';
statusEl.innerHTML = '🔄 Подключение к Redis SSE...';
// Подключаемся к ПРОСТОМУ SSE (без SUBSCRIBE)
eventSource = new EventSource('/crm_extensions/file_storage/api/redis_sse_simple.php');
eventSource.onopen = function() {
statusEl.className = 'status connected';
statusEl.innerHTML = '🟢 Подключено к Redis SSE (Predis)';
connectionStart = Date.now();
updateConnectionTime();
connectionTimer = setInterval(updateConnectionTime, 1000);
};
eventSource.onmessage = function(e) {
try {
const event = JSON.parse(e.data);
addEvent(event);
totalEvents++;
document.getElementById('totalEvents').textContent = totalEvents;
document.getElementById('lastEventTime').textContent = event.time || new Date().toLocaleTimeString('ru-RU');
} catch (err) {
console.error('Ошибка парсинга события:', err);
}
};
eventSource.onerror = function(e) {
statusEl.className = 'status disconnected';
statusEl.innerHTML = '🔴 Отключено от Redis SSE';
if (connectionTimer) {
clearInterval(connectionTimer);
}
console.error('SSE error:', e);
// Переподключаемся через 3 секунды
setTimeout(() => {
console.log('🔄 Переподключение...');
reconnect();
}, 3000);
};
}
function reconnect() {
if (eventSource) {
eventSource.close();
}
if (connectionTimer) {
clearInterval(connectionTimer);
}
connect();
}
function addEvent(event) {
const eventsEl = document.getElementById('events');
const eventEl = document.createElement('div');
eventEl.className = 'event ' + (event.type || 'unknown');
eventEl.innerHTML = `
<span class="time">${event.time || new Date().toLocaleTimeString('ru-RU')}</span>
<div class="type">📡 ${event.type || 'unknown'}</div>
<div class="data">${JSON.stringify(event.data, null, 2)}</div>
`;
eventsEl.insertBefore(eventEl, eventsEl.firstChild);
// Ограничиваем количество отображаемых событий
while (eventsEl.children.length > 20) {
eventsEl.removeChild(eventsEl.lastChild);
}
}
function updateConnectionTime() {
const seconds = Math.floor((Date.now() - connectionStart) / 1000);
document.getElementById('connectionTime').textContent = seconds + 's';
}
function sendTestEvent() {
// Отправляем тестовое событие через Redis CLI
fetch('/crm_extensions/file_storage/api/send_test_event.php')
.then(response => response.json())
.then(data => {
console.log('✅ Тестовое событие отправлено:', data);
})
.catch(err => {
console.error('❌ Ошибка отправки:', err);
});
}
function clearEvents() {
document.getElementById('events').innerHTML = '';
totalEvents = 0;
document.getElementById('totalEvents').textContent = '0';
}
// Автоматическое подключение при загрузке
connect();
</script>
</body>
</html>