nas / templates /messages.html
Starchik1's picture
Upload 25 files
9da4125 verified
{% extends 'base.html' %}
{% block title %}Сообщения{% endblock %}
{% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/messages.css') }}">
<script src="{{ url_for('static', filename='js/chat.js') }}"></script>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="row">
<!-- Список контактов (боковая панель) -->
<div class="col-md-3">
<div class="card">
<div class="card-header pb-0">
<h6>Контакты</h6>
<div class="input-group mb-3">
<input type="text" id="contactSearch" class="form-control" placeholder="Поиск...">
<span class="input-group-text"><i class="fas fa-search"></i></span>
</div>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush" id="contactsList">
{% for c in contacts %}
<a href="{{ url_for('messages', contact_id=c.contact_id) }}" class="list-group-item list-group-item-action {% if c.contact_id == contact.contact_id %}active{% endif %}">
<div class="d-flex w-100 justify-content-between align-items-center">
<h6 class="mb-1">{{ c.username }}</h6>
{% if c.unread_count > 0 %}
<span class="badge bg-danger">{{ c.unread_count }}</span>
{% endif %}
</div>
</a>
{% endfor %}
{% if contacts|length == 0 %}
<div class="text-center py-3">
<p class="text-muted">Нет контактов</p>
<a href="{{ url_for('contacts') }}" class="btn btn-sm btn-primary">
<i class="fas fa-user-plus"></i> Добавить контакты
</a>
</div>
{% endif %}
</div>
</div>
<div class="card-footer">
<a href="{{ url_for('contacts') }}" class="btn btn-sm btn-primary w-100">
<i class="fas fa-users"></i> Управление контактами
</a>
</div>
</div>
</div>
<!-- Область сообщений -->
<div class="col-md-9">
<div class="card">
{% if contact %}
<div class="card-header pb-0">
<div class="d-flex justify-content-between align-items-center">
<h6>Чат с {{ contact.username }}</h6>
</div>
</div>
<div class="card-body">
<div class="chat-messages" id="chatMessages" style="height: 400px; overflow-y: auto;">
{% if messages|length > 0 %}
{% for message in messages %}
<div class="message {% if message.sender_id == user_id %}message-sent{% else %}message-received{% endif %} mb-3" data-message-id="{{ message.id }}">
<div class="message-content p-3 rounded {% if message.sender_id == user_id %}bg-primary text-white{% else %}bg-light{% endif %}">
{{ message.content }}
{% if message.attachment_id %}
<div class="message-attachment mt-2">
{% set attachment = get_file_by_id(message.attachment_id) %}
{% if attachment %}
<div class="attachment-info">
<i class="fas {% if attachment.file_type == 'image' %}fa-image{% elif attachment.file_type == 'video' %}fa-video{% elif attachment.file_type == 'audio' %}fa-music{% elif attachment.file_type == 'text' %}fa-file-alt{% else %}fa-file{% endif %}"></i>
<a href="{{ url_for('download_file', file_id=attachment.id) }}" class="attachment-link">
{{ attachment.original_filename }}
</a>
<span class="attachment-size">{{ format_size(attachment.size) }}</span>
</div>
{% if attachment.file_type == 'image' %}
<div class="attachment-preview mt-2">
<a href="{{ url_for('download_file', file_id=attachment.id) }}" target="_blank">
<img src="{{ url_for('download_file', file_id=attachment.id) }}" class="img-thumbnail" style="max-width: 200px; max-height: 200px;">
</a>
</div>
{% elif attachment.file_type == 'video' %}
<div class="attachment-preview mt-2">
<video controls class="img-thumbnail" style="max-width: 250px; max-height: 250px;">
<source src="{{ url_for('download_file', file_id=attachment.id) }}" type="video/mp4">
Ваш браузер не поддерживает видео.
</video>
</div>
{% elif attachment.file_type == 'audio' %}
<div class="attachment-preview mt-2">
<audio controls style="max-width: 250px;">
<source src="{{ url_for('download_file', file_id=attachment.id) }}">
Ваш браузер не поддерживает аудио.
</audio>
</div>
{% endif %}
{% endif %}
</div>
{% endif %}
<div class="message-time text-end">
<small class="{% if message.sender_id == user_id %}text-white-50{% else %}text-muted{% endif %}">
{{ message.created_at }}
{% if message.sender_id == user_id %}
{% if message.is_read %}
<i class="fas fa-check-double"></i>
{% else %}
<i class="fas fa-check"></i>
{% endif %}
{% endif %}
</small>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-5">
<p class="text-muted">Нет сообщений. Начните общение!</p>
</div>
{% endif %}
</div>
</div>
<div class="card-footer">
<form action="{{ url_for('send_message', contact_id=contact.contact_id) }}" method="post" id="messageForm" enctype="multipart/form-data">
<div class="input-group">
<input type="text" name="content" class="form-control" placeholder="Введите сообщение..." required>
<label for="attachment" class="btn btn-outline-secondary" title="Прикрепить файл">
<i class="fas fa-paperclip"></i>
<input type="file" name="attachment" id="attachment" style="display: none;">
</label>
<button type="submit" class="btn btn-primary">
<i class="fas fa-paper-plane"></i> Отправить
</button>
</div>
<div id="attachment-preview" class="mt-2" style="display: none;">
<span class="badge bg-secondary"><span id="file-name"></span> <i class="fas fa-times" onclick="removeAttachment()"></i></span>
</div>
</form>
</div>
{% else %}
<div class="card-body text-center py-5">
<h5 class="text-muted">Выберите контакт для начала общения</h5>
<a href="{{ url_for('contacts') }}" class="btn btn-primary mt-3">
<i class="fas fa-user-plus"></i> Управление контактами
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Модальное окно для полноэкранного просмотра медиафайлов -->
<div class="modal fade" id="mediaModal" tabindex="-1" aria-labelledby="mediaModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mediaModalLabel">Просмотр медиафайла</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-body d-flex align-items-center justify-content-center">
<div id="mediaContent" class="text-center"></div>
</div>
</div>
</div>
</div>
<style>
.message-sent {
display: flex;
justify-content: flex-end;
}
.message-received {
display: flex;
justify-content: flex-start;
}
.message-content {
max-width: 70%;
word-wrap: break-word;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Обработчик для открытия изображений и видео в полноэкранном режиме
const mediaModal = new bootstrap.Modal(document.getElementById('mediaModal'));
// Обработка прикрепления файлов
const attachmentInput = document.getElementById('attachment');
if (attachmentInput) {
attachmentInput.addEventListener('change', function(e) {
const fileName = e.target.files[0] ? e.target.files[0].name : '';
if (fileName) {
document.getElementById('file-name').textContent = fileName;
document.getElementById('attachment-preview').style.display = 'block';
} else {
document.getElementById('attachment-preview').style.display = 'none';
}
});
}
// Функция для удаления прикрепленного файла
window.removeAttachment = function() {
if (attachmentInput) {
attachmentInput.value = '';
document.getElementById('attachment-preview').style.display = 'none';
}
};
// Прокрутка чата вниз при загрузке страницы
const chatMessages = document.getElementById('chatMessages');
if (chatMessages) {
chatMessages.scrollTop = chatMessages.scrollHeight;
}
// Поиск по контактам
const contactSearch = document.getElementById('contactSearch');
if (contactSearch) {
contactSearch.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
const contacts = document.querySelectorAll('#contactsList .list-group-item');
contacts.forEach(contact => {
const contactName = contact.querySelector('h6').textContent.toLowerCase();
if (contactName.includes(searchTerm)) {
contact.style.display = '';
} else {
contact.style.display = 'none';
}
});
});
}
// Автоматическое обновление счетчика непрочитанных сообщений
function updateUnreadCount() {
fetch('/get_unread_count')
.then(response => response.json())
.then(data => {
const unreadBadge = document.getElementById('unreadBadge');
if (unreadBadge) {
if (data.unread_count > 0) {
unreadBadge.textContent = data.unread_count;
unreadBadge.style.display = 'inline';
} else {
unreadBadge.style.display = 'none';
}
}
})
.catch(error => console.error('Ошибка при обновлении счетчика:', error));
}
// Обновление каждые 30 секунд
setInterval(updateUnreadCount, 30000);
// Инициализация автоматического обновления сообщений
{% if contact %}
initChatUpdater({{ contact.contact_id }});
// Функция для инициализации обработчиков медиафайлов
function initMediaHandlers() {
// Обработка клика по изображениям
document.querySelectorAll('.attachment-preview img').forEach(img => {
if (!img.hasAttribute('data-media-initialized')) {
img.setAttribute('data-media-initialized', 'true');
img.style.cursor = 'pointer';
img.addEventListener('click', function(e) {
e.preventDefault();
const imgSrc = this.src;
const mediaContent = document.getElementById('mediaContent');
mediaContent.innerHTML = `<img src="${imgSrc}" class="img-fluid" alt="Изображение">`;
document.getElementById('mediaModalLabel').textContent = 'Просмотр изображения';
mediaModal.show();
});
}
});
// Обработка клика по видео
document.querySelectorAll('.attachment-preview video').forEach(video => {
if (!video.hasAttribute('data-media-initialized')) {
video.setAttribute('data-media-initialized', 'true');
video.style.cursor = 'pointer';
video.addEventListener('click', function(e) {
e.preventDefault();
const videoSrc = this.querySelector('source').src || this.src;
const mediaContent = document.getElementById('mediaContent');
mediaContent.innerHTML = `<video controls class="img-fluid" autoplay><source src="${videoSrc}">Ваш браузер не поддерживает видео.</video>`;
document.getElementById('mediaModalLabel').textContent = 'Просмотр видео';
mediaModal.show();
});
}
});
}
// Вызываем функцию при загрузке страницы
initMediaHandlers();
// Добавляем обработчик для новых сообщений
document.addEventListener('chatUpdated', function() {
initMediaHandlers();
});
{% endif %}
// Остановка обновления при уходе со страницы
window.addEventListener('beforeunload', function() {
stopChatUpdater();
});
});
</script>
{% endblock %}