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: