diff --git a/public/main.js b/public/main.js index 1a2a68c..07e5d09 100644 --- a/public/main.js +++ b/public/main.js @@ -127,7 +127,22 @@ async function createTask(event) { alert('Выберите хотя бы одного исполнителя'); return; } - + // Дополнительная проверка для задач типа "document" + if (taskType === 'document' && selectedUsers.length > 0) { + // Проверяем, что все выбранные пользователи - секретари + for (const userId of selectedUsers) { + const groups = await getUserGroups(userId); + const hasSecretaryGroup = groups.some(group => + group.name === 'Секретарь' || + (typeof group === 'string' && group.includes('Секретарь')) + ); + + if (!hasSecretaryGroup) { + alert('Для задач типа "Согласование документа" можно выбирать только пользователей из группы "Секретарь"'); + return; + } + } + } const formData = new FormData(); formData.append('title', title); formData.append('description', description); diff --git a/public/ui.js b/public/ui.js index cb8fc4e..eb363a9 100644 --- a/public/ui.js +++ b/public/ui.js @@ -650,7 +650,7 @@ async function loadTaskFiles(taskId) { } // Функция для выбора типа задачи -function selectTaskType(type) { +async function selectTaskType(type) { // Убираем активный класс со всех кнопок document.querySelectorAll('.task-type-btn').forEach(btn => { btn.classList.remove('active'); @@ -666,8 +666,66 @@ function selectTaskType(type) { updateTaskFormBasedOnType(type); // Предлагаем заголовок по умолчанию suggestDefaultTitle(type); + + // Для типа "document" перезагружаем пользователей с фильтрацией + if (type === 'document') { + await reloadUsersForDocumentType(); + } else { + // Для других типов перезагружаем обычных пользователей + await loadUsers(); + } +} +// функция для перезагрузки пользователей для типа "document" +async function reloadUsersForDocumentType() { + try { + const response = await fetch('/api/users'); + const allUsersData = await response.json(); + + // Фильтруем только пользователей из группы "Секретарь" + const secretaries = []; + for (const user of allUsersData) { + if (user.id === currentUser.id) continue; + + const groups = await getUserGroups(user.id); + const hasSecretaryGroup = groups.some(group => + group.name === 'Секретарь' || + (typeof group === 'string' && group.includes('Секретарь')) + ); + + if (hasSecretaryGroup) { + secretaries.push(user); + } + } + + users = secretaries; + filteredUsers = [...users]; + renderUsersChecklist(); + + } catch (error) { + console.error('Ошибка загрузки секретарей:', error); + } +} +// Используем кэширование, чтобы не делать лишние запросы +async function getUserGroups(userId) { + // Используем кэширование, чтобы не делать лишние запросы + if (!window.userGroupsCache) window.userGroupsCache = {}; + + if (window.userGroupsCache[userId]) { + return window.userGroupsCache[userId]; + } + + try { + const response = await fetch(`/api2/idusers/user/${userId}/groups`); + if (!response.ok) return []; + + const groups = await response.json(); + window.userGroupsCache[userId] = groups || []; + return window.userGroupsCache[userId]; + } catch (error) { + console.error('Ошибка получения групп пользователя:', error); + return []; + } } - // Функция для предложения заголовка по умолчанию function suggestDefaultTitle(type) { const titleField = document.getElementById('title'); @@ -695,6 +753,7 @@ function suggestDefaultTitle(type) { // Функция для обновления формы в зависимости от типа задачи function updateTaskFormBasedOnType(type) { const userSearchField = document.getElementById('user-search'); + const taskTypeInfo = document.getElementById('task-type-info'); // Устанавливаем заголовки placeholder для поиска исполнителей const defaultPlaceholders = { @@ -713,7 +772,22 @@ function updateTaskFormBasedOnType(type) { if (userSearchField) { userSearchField.placeholder = defaultPlaceholders[type] || 'Поиск исполнителей...'; } - + // Показываем информацию о типе задачи + if (taskTypeInfo) { + const typeInfo = { + 'regular': 'Доступны все пользователи в зависимости от ваших прав', + 'document': 'Доступны только пользователи из группы "Секретарь"', + 'it': 'Доступны ИТ специалисты', + 'ahch': 'Доступны сотрудники АХЧ', + 'psychologist': 'Доступны психологи', + 'speech_therapist': 'Доступны логопеды', + 'hr': 'Доступны сотрудники кадровой службы', + 'certificate': 'Доступны секретари и завучи', + 'e_journal': 'Доступны администраторы электронного журнала' + }; + + taskTypeInfo.textContent = typeInfo[type] || ''; + } // Показываем/скрываем дополнительные поля в зависимости от типа showAdditionalFieldsForType(type); } diff --git a/public/users.js b/public/users.js index e23944c..6447866 100644 --- a/public/users.js +++ b/public/users.js @@ -6,6 +6,9 @@ let selectedUsers = []; let editSelectedUsers = []; let copySelectedUsers = []; +// Добавьте переменную для хранения групп пользователей +let userGroupsCache = {}; + async function loadUsers() { try { const response = await fetch('/api/users'); @@ -24,9 +27,49 @@ async function loadUsers() { console.error('Ошибка загрузки пользователей:', error); } } -function filterAssignableUsers(allUsers) { + +// Добавьте функцию для получения групп пользователя +async function getUserGroups(userId) { + if (userGroupsCache[userId]) { + return userGroupsCache[userId]; + } + + try { + const response = await fetch(`/api2/idusers/user/${userId}/groups`); + if (!response.ok) return []; + + const groups = await response.json(); + userGroupsCache[userId] = groups || []; + return userGroupsCache[userId]; + } catch (error) { + console.error('Ошибка получения групп пользователя:', error); + return []; + } +} + +// Обновите функцию filterAssignableUsers +function filterAssignableUsers(allUsers, taskType = 'regular') { if (!currentUser) return []; + // Для задач типа "document" - только пользователи из группы "Секретарь" + if (taskType === 'document') { + return allUsers.filter(async (user) => { + if (user.id === currentUser.id) return false; + + // Получаем группы пользователя + const groups = await getUserGroups(user.id); + + // Проверяем, есть ли группа "Секретарь" + const hasSecretaryGroup = groups.some(group => + group.name === 'Секретарь' || + (typeof group === 'string' && group.includes('Секретарь')) + ); + + return hasSecretaryGroup; + }); + } + + // Для других типов задач - обычная фильтрация // Администратор видит всех пользователей if (currentUser.role === 'admin') { return allUsers.filter(user => user.id !== currentUser.id); @@ -67,77 +110,8 @@ function filterAssignableUsers(allUsers) { user.id !== currentUser.id ); } - // Проверяем группы пользователя для определения прав - const userGroups = currentUser.groups || []; - // Загружаем конфигурацию групп из настроек - // (предполагается, что эти переменные определены в глобальной области) - const allowedGroups = getGroupsForCurrentUser(); - - // Если у пользователя нет специальных групп, возвращаем пустой массив - if (allowedGroups.length === 0) { - return []; - } - - // Фильтруем пользователей по группам - return allUsers.filter(user => { - // Пользователь не может назначать задачи себе - if (user.id === currentUser.id) return false; - - // Если у пользователя есть группы, проверяем пересечение - if (user.groups && Array.isArray(user.groups)) { - return user.groups.some(group => allowedGroups.includes(group)); - } - - return false; - }); -} - -// Функция для получения групп, которым текущий пользователь может назначать задачи -function getGroupsForCurrentUser() { - const allowedGroups = []; - const userGroups = currentUser.groups || []; - - // Определяем, какие группы доступны для назначения - // На основе ролей и групп текущего пользователя - - // Пример: пользователи с ролью 'secretary' могут назначать задачи группам 'teachers' - if (currentUser.role === 'secretary') { - allowedGroups.push('teachers', 'staff'); - } - - // Пример: пользователи из группы 'department_head' могут назначать своей группе - if (userGroups.includes('department_head')) { - allowedGroups.push('department_head', 'teachers'); - } - - // Пример: для помощи (help) можно назначать всем - if (currentUser.role === 'help') { - // Можно указать конкретные группы или 'all' для всех - allowedGroups.push('teachers', 'staff', 'administration'); - } - - // Пример: для IT поддержки - if (currentUser.role === 'ithelp') { - allowedGroups.push('teachers', 'staff', 'administration', 'it_department'); - } - - // Пример: пользователи с ролью 'request' могут создавать заявки для всех - if (currentUser.role === 'request') { - allowedGroups.push('all'); // Специальное значение "все" - } - - // Пример: пользователи с ролью 'tasks' (задачи) могут назначать учителям - if (currentUser.role === 'tasks') { - allowedGroups.push('teachers'); - } - - // Если массив содержит 'all', возвращаем специальный маркер - if (allowedGroups.includes('all')) { - return ['all']; // Это будет обрабатываться в фильтрации - } - - return [...new Set(allowedGroups)]; // Убираем дубликаты + return []; } function populateFilterDropdowns() { const creatorFilter = document.getElementById('creator-filter'); @@ -157,33 +131,119 @@ function populateFilterDropdowns() { }); } -function filterUsers() { +// Обновите функцию filterUsers с учетом типа задачи +async function filterUsers() { const search = document.getElementById('user-search').value.toLowerCase(); - filteredUsers = users.filter(user => - user.name.toLowerCase().includes(search) || - user.login.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search) - ); + 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('Секретарь')) + ); + + if (hasSecretaryGroup) { + filteredUsers.push(user); + } + } + } else { + // Обычная фильтрация для других типов задач + filteredUsers = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); + } + renderUsersChecklist(); } -function filterEditUsers() { +async function filterEditUsers() { const search = document.getElementById('edit-user-search').value.toLowerCase(); - const filtered = users.filter(user => - user.name.toLowerCase().includes(search) || - user.login.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search) - ); + const task = tasks.find(t => t.id === document.getElementById('edit-task-id').value); + const taskType = task ? task.task_type : 'regular'; + + let filtered = []; + + if (taskType === 'document') { + // Для задач типа "document" - только секретари + let tempFiltered = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); + + filtered = []; + for (const user of tempFiltered) { + const groups = await getUserGroups(user.id); + const hasSecretaryGroup = groups.some(group => + group.name === 'Секретарь' || + (typeof group === 'string' && group.includes('Секретарь')) + ); + + if (hasSecretaryGroup) { + filtered.push(user); + } + } + } else { + filtered = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); + } + renderEditUsersChecklist(filtered); } -function filterCopyUsers() { +async function filterCopyUsers() { const search = document.getElementById('copy-user-search').value.toLowerCase(); - const filtered = users.filter(user => - user.name.toLowerCase().includes(search) || - user.login.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search) - ); + const taskId = document.getElementById('copy-task-id').value; + const task = tasks.find(t => t.id === taskId); + const taskType = task ? task.task_type : 'regular'; + + let filtered = []; + + if (taskType === 'document') { + // Для задач типа "document" - только секретари + let tempFiltered = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); + + filtered = []; + for (const user of tempFiltered) { + const groups = await getUserGroups(user.id); + const hasSecretaryGroup = groups.some(group => + group.name === 'Секретарь' || + (typeof group === 'string' && group.includes('Секретарь')) + ); + + if (hasSecretaryGroup) { + filtered.push(user); + } + } + } else { + filtered = users.filter(user => + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) + ); + } + renderCopyUsersChecklist(filtered); } @@ -197,6 +257,8 @@ function renderUsersChecklist() { ${user.name} + ${document.getElementById('task-type').value === 'document' ? + '(Секретарь)' : ''} `).join('');