diff --git a/frontend/src/components/ContactTable.vue b/frontend/src/components/ContactTable.vue index 26fa7a7..846c225 100644 --- a/frontend/src/components/ContactTable.vue +++ b/frontend/src/components/ContactTable.vue @@ -26,7 +26,7 @@ Импорт - + @@ -204,29 +204,64 @@ const hasSelectedEditor = computed(() => { }); }); -// Фильтрация контактов для USER - видит только editor админов и себя +// Фильтры формы доступны только для роли editor +const isEditorRole = computed(() => userAccessLevel.value?.level === 'editor'); + +// Фильтрация контактов: по роли (user/readonly/editor), для editor — дополнительно по форме фильтров const filteredContacts = computed(() => { - console.log('[ContactTable] 🔍 Фильтрация контактов:'); - console.log('[ContactTable] userAccessLevel:', userAccessLevel.value); - console.log('[ContactTable] userId:', userId.value); - console.log('[ContactTable] Все контакты:', contactsArray.value); - + let list; if (userAccessLevel.value?.level === 'user') { // USER видит только editor админов и себя - const filtered = contactsArray.value.filter(contact => { - const isEditor = contact.role === 'editor'; // Используем role вместо contact_type + list = contactsArray.value.filter(contact => { + const isEditor = contact.role === 'editor'; const isSelf = contact.id === userId.value; - console.log(`[ContactTable] Контакт ${contact.id}: role=${contact.role}, contact_type=${contact.contact_type}, isEditor=${isEditor}, isSelf=${isSelf}`); - console.log(`[ContactTable] Полный объект контакта:`, contact); return isEditor || isSelf; }); - console.log('[ContactTable] Отфильтрованные контакты:', filtered); - return filtered; + } else { + // READONLY и EDITOR видят всех + list = [...contactsArray.value]; } - - // READONLY и EDITOR видят всех - console.log('[ContactTable] Показываем всех (не user роль)'); - return contactsArray.value; + + // Фильтры формы применяем только для роли editor + if (!isEditorRole.value) return list; + + return list.filter(contact => { + if (filterSearch.value) { + const q = filterSearch.value.toLowerCase(); + const name = (contact.name || '').toLowerCase(); + const email = (contact.email || '').toLowerCase(); + const telegram = (contact.telegram || '').toLowerCase(); + const wallet = (contact.wallet || '').toLowerCase(); + if (!name.includes(q) && !email.includes(q) && !telegram.includes(q) && !wallet.includes(q)) return false; + } + if (filterContactType.value && filterContactType.value !== 'all') { + const ct = (contact.contact_type || '').toLowerCase(); + if (ct !== filterContactType.value) return false; + } + if (filterDateFrom.value) { + const created = contact.created_at ? new Date(contact.created_at) : null; + const from = new Date(filterDateFrom.value); + from.setHours(0, 0, 0, 0); + if (!created || created < from) return false; + } + if (filterDateTo.value) { + const created = contact.created_at ? new Date(contact.created_at) : null; + const to = new Date(filterDateTo.value); + to.setHours(23, 59, 59, 999); + if (!created || created > to) return false; + } + if (filterNewMessages.value === 'yes') { + if (!newMsgUserIds.value.includes(String(contact.id))) return false; + } + if (filterBlocked.value === 'blocked' && !contact.is_blocked) return false; + if (filterBlocked.value === 'unblocked' && contact.is_blocked) return false; + if (selectedTagIds.value.length > 0) { + const contactTagIds = contact.tag_ids || (contact.tags || []).map(t => t.id || t); + const hasMatch = selectedTagIds.value.some(tid => contactTagIds.includes(tid)); + if (!hasMatch) return false; + } + return true; + }); }); // WebSocket для тегов - ОТКЛЮЧАЕМ из-за циклических запросов diff --git a/webssh-agent/docker-compose.prod.yml b/webssh-agent/docker-compose.prod.yml index 89a9333..a937e0f 100644 --- a/webssh-agent/docker-compose.prod.yml +++ b/webssh-agent/docker-compose.prod.yml @@ -62,7 +62,8 @@ services: - OLLAMA_NUM_GPU=0 - OLLAMA_KEEP_ALIVE=86400 - OLLAMA_MODEL_TIMEOUT=0 - - OLLAMA_MAX_LOADED_MODELS=2 + # 1 модель в RAM: при 2 моделях free≈4.1 GiB, qwen2.5:7b нужно 4.5 GiB → Load failed + - OLLAMA_MAX_LOADED_MODELS=1 - OLLAMA_FLASH_ATTENTION=0 - OLLAMA_LLM_LIBRARY=auto healthcheck: @@ -108,6 +109,9 @@ services: backend: image: digital_legal_entitydle-backend:latest + build: + context: ./backend + dockerfile: Dockerfile container_name: dapp-backend restart: unless-stopped networks: @@ -174,6 +178,9 @@ services: frontend: image: digital_legal_entitydle-frontend:latest + build: + context: ./frontend + dockerfile: Dockerfile container_name: dapp-frontend restart: unless-stopped networks: @@ -229,6 +236,9 @@ services: # Nginx с автоматическим SSL и поддержкой WebSocket frontend-nginx: image: digital_legal_entitydle-frontend-nginx:latest + build: + context: ./frontend + dockerfile: nginx.Dockerfile container_name: dapp-frontend-nginx restart: unless-stopped networks: