feat: новая функция

This commit is contained in:
2025-10-16 18:44:30 +03:00
parent e0300480e1
commit 927d174f66
33 changed files with 1494 additions and 700 deletions

View File

@@ -235,7 +235,9 @@ const updateAuth = async ({
if (!isAuthenticated.value && wasAuthenticated) {
console.log('[useAuth] User logged out, clearing application data');
// Очищаем глобальные данные приложения
window.dispatchEvent(new CustomEvent('clear-application-data'));
const event = new CustomEvent('clear-application-data');
console.log('[useAuth] Dispatching clear-application-data event:', event);
window.dispatchEvent(event);
}
// Централизованное обновление данных при подключении
@@ -436,8 +438,8 @@ const disconnect = async () => {
// Удаляем все идентификаторы перед выходом
await axios.post('/auth/logout');
// Обновляем состояние в памяти
updateAuth({
// Обновляем состояние в памяти через updateAuth (это запустит централизованные события)
await updateAuth({
authenticated: false,
authType: null,
userId: null,

View File

@@ -15,6 +15,7 @@ import api from '../api/axios';
import { getFromStorage, setToStorage, removeFromStorage } from '../utils/storage';
import { generateUniqueId } from '../utils/helpers';
import websocketModule from '../services/websocketService';
import { getPublicMessages } from '../services/messagesService';
const { websocketService } = websocketModule;
@@ -104,7 +105,7 @@ export function useChat(auth) {
let totalMessages = -1;
if (initial || messageLoading.value.offset === 0) {
try {
const countResponse = await api.get('/chat/history', { params: { count_only: true } });
const countResponse = await api.get('/messages/public', { params: { count_only: true } });
if (!countResponse.data.success) throw new Error('Не удалось получить количество сообщений');
totalMessages = countResponse.data.total || countResponse.data.count || 0;
// console.log(`[useChat] Всего сообщений в истории: ${totalMessages}`);
@@ -121,15 +122,17 @@ export function useChat(auth) {
// console.log(`[useChat] Рассчитано начальное смещение: ${effectiveOffset}`);
}
const response = await api.get('/chat/history', {
params: {
offset: effectiveOffset,
limit: messageLoading.value.limit,
},
// Используем новый API для публичных сообщений с пагинацией
const response = await api.get('/messages/public', {
params: {
offset: effectiveOffset,
limit: messageLoading.value.limit
}
});
if (response.data.success) {
const loadedMessages = response.data.messages || [];
if (response.data.success && response.data.messages) {
const loadedMessages = response.data.messages;
const totalFromResponse = response.data.total;
// console.log(`[useChat] Загружено ${loadedMessages.length} сообщений.`);
if (loadedMessages.length > 0) {
@@ -142,7 +145,7 @@ export function useChat(auth) {
// Обновляем смещение для следующей загрузки
// Если загружали последние, offset = total - limit + loaded
if (initial && totalMessages > 0 && effectiveOffset > 0) {
if (initial && totalFromResponse > 0 && effectiveOffset > 0) {
messageLoading.value.offset = effectiveOffset + loadedMessages.length;
} else {
messageLoading.value.offset += loadedMessages.length;
@@ -150,12 +153,12 @@ export function useChat(auth) {
// console.log(`[useChat] Новое смещение: ${messageLoading.value.offset}`);
// Проверяем, есть ли еще сообщения для загрузки
// Используем totalMessages, если он был успешно получен
if (totalMessages >= 0) {
messageLoading.value.hasMoreMessages = messageLoading.value.offset < totalMessages;
// Используем totalFromResponse из нового API
if (totalFromResponse >= 0) {
messageLoading.value.hasMoreMessages = messageLoading.value.offset < totalFromResponse;
} else {
// Если total не известен, считаем, что есть еще, если загрузили полный лимит
messageLoading.value.hasMoreMessages = loadedMessages.length === messageLoading.value.limit;
// Если total не известен, используем hasMore из ответа
messageLoading.value.hasMoreMessages = response.data.hasMore || false;
}
// console.log(`[useChat] Есть еще сообщения: ${messageLoading.value.hasMoreMessages}`);
} else {

View File

@@ -12,7 +12,7 @@
import { ref, onMounted, onUnmounted } from 'vue';
import { getContacts } from '../services/contactsService';
import { getAllMessages } from '../services/messagesService';
import { getPublicMessages } from '../services/messagesService';
import axios from 'axios';
export function useContactsAndMessagesWebSocket() {
@@ -111,9 +111,19 @@ export function useContactsAndMessagesWebSocket() {
}
async function fetchMessages() {
const all = await getAllMessages();
messages.value = all;
filterNewMessages();
try {
// Используем новый API для публичных сообщений с пагинацией
const response = await getPublicMessages(null, { limit: 50, offset: 0 });
if (response.success && response.messages) {
messages.value = response.messages;
filterNewMessages();
} else {
messages.value = [];
}
} catch (error) {
console.error('[useContactsWebSocket] Ошибка загрузки публичных сообщений:', error);
messages.value = [];
}
}
function markMessagesAsRead() {
@@ -170,6 +180,18 @@ export function useContactsAndMessagesWebSocket() {
lastReadMessageDate.value = {};
}
// Подписываемся на централизованные события очистки и обновления данных
window.addEventListener('clear-application-data', () => {
console.log('[useContactsWebSocket] Received clear-application-data event, clearing contacts data');
clearContactsData(); // Очищаем данные при выходе из системы
console.log('[useContactsWebSocket] Contacts data cleared successfully');
});
window.addEventListener('refresh-application-data', () => {
console.log('[useContactsWebSocket] Refreshing contacts data');
fetchContacts(); // Обновляем данные при входе в систему
});
// Централизованная подписка на изменения аутентификации
onMounted(async () => {
await fetchContactsReadStatus();
@@ -177,17 +199,6 @@ export function useContactsAndMessagesWebSocket() {
await fetchReadStatus();
await fetchMessages();
setupWebSocket();
// Подписываемся на централизованные события очистки и обновления данных
window.addEventListener('clear-application-data', () => {
console.log('[useContactsWebSocket] Clearing contacts data');
clearContactsData(); // Очищаем данные при выходе из системы
});
window.addEventListener('refresh-application-data', () => {
console.log('[useContactsWebSocket] Refreshing contacts data');
fetchContacts(); // Обновляем данные при входе в систему
});
});
onUnmounted(() => {
if (ws) ws.close();

View File

@@ -0,0 +1,104 @@
import { ref, computed, onMounted, onUnmounted } from 'vue'
import api from '../api/axios'
const roles = ref([])
const isLoading = ref(false)
const error = ref(null)
export function useRoles() {
// Загружаем роли с сервера (из базы данных через миграции)
const fetchRoles = async () => {
try {
isLoading.value = true
error.value = null
const response = await api.get('/users/roles')
if (response.data.success) {
roles.value = response.data.roles
console.log('[useRoles] Загружены роли из базы данных:', roles.value)
} else {
throw new Error(response.data.error || 'Ошибка загрузки ролей')
}
} catch (err) {
console.error('[useRoles] Ошибка при загрузке ролей:', err)
error.value = err.message
// Не показываем ошибку если пользователь не авторизован
if (err.response?.status === 401) {
console.log('[useRoles] Пользователь не авторизован, пропускаем загрузку ролей')
error.value = null
}
} finally {
isLoading.value = false
}
}
// Получаем название роли по ID
const getRoleName = (roleId) => {
const role = roles.value.find(r => r.id === roleId)
return role ? role.name : 'Неизвестно'
}
// Получаем CSS класс для роли
const getRoleClass = (roleName) => {
const classMap = {
'user': 'user-badge',
'readonly': 'readonly-badge',
'editor': 'editor-badge'
}
return classMap[roleName] || 'user-badge'
}
// Получаем отображаемое название роли
const getRoleDisplayName = (roleName) => {
const displayMap = {
'user': 'Пользователь',
'readonly': 'Чтение',
'editor': 'Редактор'
}
return displayMap[roleName] || 'Неизвестно'
}
// Функция для очистки ролей
const clearRoles = () => {
roles.value = []
error.value = null
console.log('[useRoles] Роли очищены')
}
// Computed для проверки загрузки
const isReady = computed(() => roles.value.length > 0 && !isLoading.value)
// Подписываемся на централизованные события
const handleClearData = () => {
console.log('[useRoles] Получено событие очистки данных')
clearRoles()
}
const handleRefreshData = () => {
console.log('[useRoles] Получено событие обновления данных, загружаем роли')
fetchRoles()
}
onMounted(() => {
window.addEventListener('clear-application-data', handleClearData)
window.addEventListener('refresh-application-data', handleRefreshData)
})
onUnmounted(() => {
window.removeEventListener('clear-application-data', handleClearData)
window.removeEventListener('refresh-application-data', handleRefreshData)
})
return {
roles: computed(() => roles.value),
isLoading: computed(() => isLoading.value),
error: computed(() => error.value),
isReady,
fetchRoles,
clearRoles,
getRoleName,
getRoleClass,
getRoleDisplayName
}
}