|
{% 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));
|
|
}
|
|
|
|
|
|
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 %} |