From db2ae5a6548e6293fdddba63e748592c4f1002f6 Mon Sep 17 00:00:00 2001 From: kalugin66 Date: Fri, 13 Feb 2026 21:27:07 +0500 Subject: [PATCH] =?UTF-8?q?=D0=B8=D0=BD=D0=B4=D0=B8=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20=D1=87=D0=B5=D0=BA=D0=BB=D0=B8=D1=81=D1=82=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/style.css | 42 +++++++++++++++++ public/ui.js | 56 +++++++++++++++++++++- public/users.js | 119 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 181 insertions(+), 36 deletions(-) diff --git a/public/style.css b/public/style.css index 929ca42..27533c5 100644 --- a/public/style.css +++ b/public/style.css @@ -4378,4 +4378,46 @@ button.btn-primary { .profile-stats { grid-template-columns: 1fr; } +} +/* Добавить в CSS */ +.loading-spinner { + padding: 20px; + text-align: center; + color: #666; + font-style: italic; +} + +.no-users { + padding: 20px; + text-align: center; + color: #999; + background: #f5f5f5; + border-radius: 5px; +} + +.user-checkbox:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.checkbox-item { + transition: opacity 0.3s; +} + +.checkbox-item.loading { + opacity: 0.7; + pointer-events: none; +} + +.loading-badge { + color: #f39c12; + margin-left: 5px; + font-size: 0.8em; + animation: pulse 1.5s infinite; +} + +@keyframes pulse { + 0% { opacity: 0.6; } + 50% { opacity: 1; } + 100% { opacity: 0.6; } } \ No newline at end of file diff --git a/public/ui.js b/public/ui.js index 5bb7cb9..c1631d8 100644 --- a/public/ui.js +++ b/public/ui.js @@ -856,7 +856,7 @@ async function loadTaskFiles(taskId) { } // Функция для выбора типа задачи -async function selectTaskType(type) { +async function selectTaskType_old(type) { // Убираем активный класс со всех кнопок document.querySelectorAll('.task-type-btn').forEach(btn => { btn.classList.remove('active'); @@ -895,6 +895,60 @@ async function selectTaskType(type) { await loadUsers(); } } +// ui.js - обновить функцию selectTaskType +async function selectTaskType(type) { + // Убираем активный класс со всех кнопок + document.querySelectorAll('.task-type-btn').forEach(btn => { + btn.classList.remove('active'); + }); + + // Добавляем активный класс выбранной кнопке + const selectedBtn = document.querySelector(`.task-type-btn[data-type="${type}"]`); + if (selectedBtn) { + selectedBtn.classList.add('active'); + } + + // Устанавливаем значение в скрытое поле + document.getElementById('task-type').value = type; + + // Обновляем форму + updateTaskFormBasedOnType(type); + suggestDefaultTitle(type); + + // Очищаем выбранных пользователей при смене типа + selectedUsers = []; + + // Показываем загрузку + const checklist = document.getElementById('users-checklist'); + if (checklist) { + checklist.innerHTML = '
⏳ Загрузка доступных пользователей...
'; + } + + // Загружаем пользователей для выбранного типа + try { + if (type === 'document') { + await reloadUsersForDocumentType(); + } else if (['it', 'ahch', 'psychologist', 'speech_therapist', 'hr', 'certificate', 'e_journal'].includes(type)) { + const groupNames = { + 'it': 'ИТ специалист', + 'ahch': 'АХЧ', + 'psychologist': 'психолог', + 'speech_therapist': 'логопед', + 'hr': 'Диспетчер', + 'certificate': 'Администрация', + 'e_journal': 'Админ ЭЖ' + }; + await reloadUsersForType(groupNames[type]); + } else { + await loadUsers(); + } + } catch (error) { + console.error('Ошибка загрузки пользователей:', error); + if (checklist) { + checklist.innerHTML = '
Ошибка загрузки пользователей
'; + } + } +} // функция для перезагрузки пользователей для типа "document" async function reloadUsersForDocumentType() { try { diff --git a/public/users.js b/public/users.js index c3db072..e2a0438 100644 --- a/public/users.js +++ b/public/users.js @@ -5,6 +5,8 @@ let filteredUsers = []; let selectedUsers = []; let editSelectedUsers = []; let copySelectedUsers = []; +// добавить переменную для отслеживания загрузки +let isUsersLoading = false; // Добавьте переменную для хранения групп пользователей let userGroupsCache = {}; @@ -150,41 +152,65 @@ function populateFilterDropdowns() { // Обновите функцию filterUsers с учетом типа задачи async function filterUsers() { - const search = document.getElementById('user-search').value.toLowerCase(); - const taskType = document.getElementById('task-type').value || 'regular'; + const search = document.getElementById('user-search')?.value.toLowerCase() || ''; + const taskType = document.getElementById('task-type')?.value || 'regular'; - // Для задач типа "document" нужна особая фильтрация - if (taskType === 'document') { - // Сначала фильтруем по поисковому запросу - let tempFiltered = users.filter(user => - user.name.toLowerCase().includes(search) || - user.login.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search) - ); - - // Затем проверяем группы для каждого пользователя - filteredUsers = []; - for (const user of tempFiltered) { - const groups = await getUserGroups(user.id); - const hasSecretaryGroup = groups.some(group => - group.name === 'Секретарь' || - (typeof group === 'string' && group.includes('Секретарь')) + isUsersLoading = true; + renderUsersChecklist(); // Показываем загрузку + + try { + if (taskType === 'document' || taskType === 'it' || taskType === 'ahch' || + taskType === 'psychologist' || taskType === 'speech_therapist' || + taskType === 'hr' || taskType === 'certificate' || taskType === 'e_journal') { + + // Фильтруем по поиску + let tempFiltered = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) ); - if (hasSecretaryGroup) { - filteredUsers.push(user); + // Затем проверяем группы + filteredUsers = []; + const groupNames = { + 'document': 'Секретарь', + 'it': 'ИТ специалист', + 'ahch': 'АХЧ', + 'psychologist': 'психолог', + 'speech_therapist': 'логопед', + 'hr': 'Диспетчер', + 'certificate': 'Администрация', + 'e_journal': 'Админ ЭЖ' + }; + + const targetGroup = groupNames[taskType]; + + for (const user of tempFiltered) { + const groups = await getUserGroups(user.id); + const hasTargetGroup = groups.some(group => + group.name === targetGroup || + (typeof group === 'string' && group.includes(targetGroup)) + ); + + if (hasTargetGroup) { + filteredUsers.push(user); + } } + } else { + // Обычная фильтрация + filteredUsers = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); } - } else { - // Обычная фильтрация для других типов задач - filteredUsers = users.filter(user => - user.name.toLowerCase().includes(search) || - user.login.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search) - ); + } catch (error) { + console.error('Ошибка фильтрации пользователей:', error); + filteredUsers = []; + } finally { + isUsersLoading = false; + renderUsersChecklist(); } - - renderUsersChecklist(); } async function filterEditUsers() { @@ -266,22 +292,45 @@ async function filterCopyUsers() { function renderUsersChecklist() { const container = document.getElementById('users-checklist'); + + if (isUsersLoading) { + container.innerHTML = '
⏳ Загрузка пользователей...
'; + return; + } + + if (!filteredUsers || filteredUsers.length === 0) { + container.innerHTML = '
Нет доступных пользователей
'; + return; + } + container.innerHTML = filteredUsers - .filter(user => user.id !== currentUser.id) + .filter(user => user.id !== currentUser?.id) .map(user => `
`).join(''); } - +// Вспомогательная функция для отображения типа пользователя +function getUserTypeLabel(user, taskType) { + const labels = { + 'document': '(Секретарь)', + 'it': '(ИТ специалист)', + 'ahch': '(АХЧ)', + 'psychologist': '(Психолог)', + 'speech_therapist': '(Логопед)', + 'hr': '(Диспетчер)', + 'certificate': '(Администрация)', + 'e_journal': '(Админ ЭЖ)' + }; + return labels[taskType] || ''; +} function renderEditUsersChecklist(filtered = users) { const container = document.getElementById('edit-users-checklist'); container.innerHTML = filtered