From 53910937cf1050d5ed3de928fbf81f73eab1d5fa Mon Sep 17 00:00:00 2001 From: Professional Date: Fri, 23 May 2025 16:02:15 +0700 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B4=D0=B8=D0=B7=D0=B0=D0=B9=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=87=D0=B0=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/ChatListView.vue | 608 +++++++++++++++++--- src/views/ChatView.vue | 1110 +++++++++++++++++++++++++----------- 2 files changed, 1303 insertions(+), 415 deletions(-) diff --git a/src/views/ChatListView.vue b/src/views/ChatListView.vue index 8d6cf4f..9a87eac 100644 --- a/src/views/ChatListView.vue +++ b/src/views/ChatListView.vue @@ -1,58 +1,117 @@ @@ -62,7 +121,7 @@ import { ref, onMounted, computed, onUnmounted } from 'vue'; import api from '@/services/api'; import { useAuth } from '@/auth'; // Для получения ID текущего пользователя import router from '@/router'; // Если понадобится редирект -import { getSocket, connectSocket } from '@/services/socketService'; // ИСПРАВЛЕННЫЙ ПУТЬ +import { getSocket, connectSocket } from '@/services/socketService'; const { user: currentUser, isAuthenticated } = useAuth(); // Получаем текущего пользователя @@ -114,7 +173,7 @@ const getUnreadCount = (conversation) => { // Fallback к старой логике, если новый счетчик 0 (или не инициализирован для старых чатов), // но lastMessage не прочитано текущим пользователем. if (currentUser.value && conversation.lastMessage && - conversation.lastMessage.sender?._id !== currentUser.value?._id && + conversation.lastMessage.sender?._id !== currentUser.value._id && (!conversation.lastMessage.readBy || !conversation.lastMessage.readBy.includes(currentUser.value._id))) { return 1; // Показываем, что есть хотя бы одно непрочитанное (последнее) } @@ -148,6 +207,7 @@ const formatLastMessage = (lastMsg) => { // Форматирование времени последнего сообщения/обновления const formatTimestamp = (timestamp) => { if (!timestamp) return ''; + const date = new Date(timestamp); const today = new Date(); const yesterday = new Date(today); @@ -166,14 +226,8 @@ const onImageError = (event, participantOnError) => { console.warn("[ChatListView] Не удалось загрузить изображение:", event.target.src, "для пользователя:", participantOnError?.name); // Устанавливаем src на заглушку из public/img, если фото не загрузилось. // Это для случая, когда mainPhotoUrl был, но оказался битым. - // Если mainPhotoUrl изначально не было, сработает v-else с иконкой. - event.target.src = defaultAvatar; - // Можно добавить класс, чтобы скрыть img и показать div-заглушку, если это необходимо, - // но обычно @error на img и последующая замена src на defaultAvatar достаточны. - // Однако, для консистенции с SwipeView, лучше убедиться, что заглушка-иконка показывается. - // Для этого можно попробовать скрыть img и показать соседний div с иконкой, - // но это усложнит логику, так как v-if/v-else уже управляют этим. - // Простейший вариант - просто заменить на defaultAvatar.png. + event.target.src = defaultAvatar; + // Если хотим именно иконку, то нужно будет менять состояние, чтобы v-else сработало. // Например, установить participantOnError.mainPhotoUrl = null; // Это вызовет обновление DOM и показ блока v-else. @@ -203,6 +257,8 @@ const handleMessagesReadInList = ({ conversationId: readConversationId, readerId const conv = conversations.value[convIndex]; // Если Я (currentUser) прочитал сообщения собеседника в этом диалоге if (readerId === currentUser.value?._id && conv.lastMessage && conv.lastMessage.sender?._id !== currentUser.value?._id) { + // Очищаем счетчик непрочитанных для этого диалога + unreadMessageCounts.value[readConversationId] = 0; if (!conv.lastMessage.readBy) conv.lastMessage.readBy = []; if (!conv.lastMessage.readBy.includes(readerId)) { conv.lastMessage.readBy.push(readerId); @@ -213,6 +269,7 @@ const handleMessagesReadInList = ({ conversationId: readConversationId, readerId // Если Собеседник прочитал НАШИ сообщения (это больше для ChatView, но если хотим обновить тут что-то) // В данном контексте (список чатов), это событие в основном означает, что МЫ прочитали, // и если у нас был индикатор непрочитанных от собеседника, он должен исчезнуть. + // Перезапрос fetchConversations() может быть слишком тяжелым. // Лучше, если сервер присылает обновленный объект диалога или мы мутируем локально. console.log(`[ChatListView] Messages read in conversation ${readConversationId}, reader: ${readerId}. Updating UI.`); @@ -312,58 +369,433 @@ onUnmounted(() => { socket.off('getMessage'); } }); + +// Функция для определения правильного склонения слова "диалог" +const getDialogsCountText = (count) => { + const remainder10 = count % 10; + const remainder100 = count % 100; + + if (remainder10 === 1 && remainder100 !== 11) { + return 'диалог'; + } else if ([2, 3, 4].includes(remainder10) && ![12, 13, 14].includes(remainder100)) { + return 'диалога'; + } else { + return 'диалогов'; + } +}; \ No newline at end of file diff --git a/src/views/ChatView.vue b/src/views/ChatView.vue index 80472d2..6aeb2d5 100644 --- a/src/views/ChatView.vue +++ b/src/views/ChatView.vue @@ -1,132 +1,208 @@ \ No newline at end of file