This commit is contained in:
2026-03-05 23:50:43 +05:00
parent 91f408aca2
commit e43688a618
3 changed files with 168 additions and 0 deletions

130
public/openTaskChat2.js Normal file
View File

@@ -0,0 +1,130 @@
// Показывает модальное окно со списком задач
function showUnreadNotification(tasks) {
const modalHtml = `
<div class="modal" id="unread-notification-modal">
<div class="modal-content" style="max-width: 500px;">
<div class="modal-header">
<h3>📬 У вас новые сообщения</h3>
<span class="close" onclick="closeUnreadNotification()">&times;</span>
</div>
<div class="modal-body">
<p>В следующих задачах есть непрочитанные сообщения:</p>
<ul style="list-style: none; padding: 0;">
${tasks.map(task => `
<li style="margin: 10px 0; padding: 10px; background: #f5f5f5; border-radius: 5px; display: flex; justify-content: space-between; align-items: center;">
<span><strong>${escapeHtml(task.title)}</strong> (${task.unreadCount} ${pluralize(task.unreadCount, ['новое сообщение', 'новых сообщения', 'новых сообщений'])})</span>
<button class="btn-primary" onclick="openTaskAndMarkRead(${task.taskId})">Открыть чат</button>
</li>
`).join('')}
</ul>
</div>
<div class="modal-footer">
<button class="btn-cancel" onclick="closeUnreadNotification()">Закрыть</button>
</div>
</div>
</div>
`;
let modal = document.getElementById('unread-notification-modal');
if (modal) modal.remove();
const container = document.createElement('div');
container.innerHTML = modalHtml;
document.body.appendChild(container);
modal = document.getElementById('unread-notification-modal');
modal.style.display = 'block';
// Добавляем стили (если ещё не добавлены)
if (!document.getElementById('unread-notification-styles')) {
const style = document.createElement('style');
style.id = 'unread-notification-styles';
style.textContent = `
#unread-notification-modal {
display: none;
position: fixed;
z-index: 1001;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
animation: fadeIn 0.3s;
}
#unread-notification-modal .modal-content {
animation: slideIn 0.3s ease-out;
background-color: #fefefe;
margin: 5% auto;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
overflow: hidden;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideIn {
from { transform: translateY(-50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
`;
document.head.appendChild(style);
}
}
function closeUnreadNotification() {
const modal = document.getElementById('unread-notification-modal');
if (modal) {
modal.style.display = 'none';
setTimeout(() => modal.remove(), 300);
}
}
// Вспомогательная функция для склонения
function pluralize(count, words) {
const cases = [2, 0, 1, 1, 1, 2];
return words[(count % 100 > 4 && count % 100 < 20) ? 2 : cases[Math.min(count % 10, 5)]];
}
// Экранирование HTML в заголовке задачи (защита от XSS)
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
// Открывает чат задачи и помечает все сообщения как прочитанные
function openTaskAndMarkRead(taskId) {
closeUnreadNotification();
// Опционально: сразу отмечаем все сообщения прочитанными
fetch(`/api/chat/tasks/${taskId}/mark-read`, { method: 'POST' })
.catch(err => console.warn('Не удалось отметить сообщения как прочитанные', err))
.finally(() => openTaskChat(taskId));
}
// Проверка наличия непрочитанных сообщений
function checkUnreadMessages() {
// Не беспокоим пользователя, если страница не активна
if (document.hidden) return;
fetch('/api/chat/unread-summary')
.then(response => {
if (response.status === 401) return null; // пользователь не авторизован
return response.json();
})
.then(data => {
if (data && data.totalUnread > 0) {
showUnreadNotification(data.tasks);
}
})
.catch(err => console.error('Ошибка проверки новых сообщений:', err));
}
// Запуск периодической проверки (раз в 5 минут)
setInterval(checkUnreadMessages, 5 * 60 * 1000);
// Проверка при загрузке страницы
document.addEventListener('DOMContentLoaded', checkUnreadMessages);