From 0b54ca8404e6b2a6302c4816084df6f5ab785616 Mon Sep 17 00:00:00 2001 From: kalugin66 Date: Mon, 2 Feb 2026 16:16:14 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=B1=D0=B5=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api-doc.js | 5 +- database.js | 5 +- public/doc-auth.js | 158 +++++++++++ public/doc-tasks.js | 227 ++++++---------- public/doc-users.js | 269 +++++++++++++------ public/doc.html | 388 +++++++++++++++------------ public/doc.js | 568 ---------------------------------------- public/index.html | 112 ++++---- public/main.js | 235 ++++++++++++++++- public/style.css | 47 ++++ public/time-selector.js | 191 ++++++++++++++ 11 files changed, 1185 insertions(+), 1020 deletions(-) create mode 100644 public/doc-auth.js delete mode 100644 public/doc.js create mode 100644 public/time-selector.js diff --git a/api-doc.js b/api-doc.js index e1324f9..c6351b6 100644 --- a/api-doc.js +++ b/api-doc.js @@ -918,4 +918,7 @@ ${files.map((f, i) => `${i + 1}. ${f.original_name} (${formatFileSize(f.file_siz } next(); } -}; \ No newline at end of file +}; + + +// diff --git a/database.js b/database.js index 428fe0a..6a29792 100644 --- a/database.js +++ b/database.js @@ -276,7 +276,8 @@ function createSQLiteTables() { rework_comment TEXT, closed_at DATETIME, closed_by INTEGER, - task_type TEXT DEFAULT 'regular', + task_type TEXT DEFAULT "regular", + type TEXT, approver_group_id INTEGER, document_id INTEGER, FOREIGN KEY (created_by) REFERENCES users (id), @@ -673,6 +674,7 @@ function checkAndUpdateTableStructure() { { name: 'closed_at', type: 'DATETIME' }, { name: 'closed_by', type: 'INTEGER' }, { name: 'task_type', type: 'TEXT DEFAULT "regular"' }, + { name: 'type', type: 'TEXT' }, { name: 'approver_group_id', type: 'INTEGER' }, { name: 'document_id', type: 'INTEGER' } ], @@ -1058,6 +1060,7 @@ async function createPostgresTables() { closed_at TIMESTAMP, closed_by INTEGER REFERENCES users(id), task_type VARCHAR(50) DEFAULT 'regular', + type VARCHAR(100), approver_group_id INTEGER, document_id INTEGER ) diff --git a/public/doc-auth.js b/public/doc-auth.js new file mode 100644 index 0000000..7b2c358 --- /dev/null +++ b/public/doc-auth.js @@ -0,0 +1,158 @@ +// auth.js - Аутентификация и авторизация +let currentUser = null; + +async function checkAuth() { + try { + const response = await fetch('/api/user'); + if (response.ok) { + const data = await response.json(); + currentUser = data.user; + showMainInterface(); + } else { + showLoginInterface(); + } + } catch (error) { + showLoginInterface(); + } +} + +function showLoginInterface() { + document.getElementById('login-modal').style.display = 'block'; + document.querySelector('.container').style.display = 'none'; +} + +function showMainInterface() { + document.getElementById('login-modal').style.display = 'none'; + document.querySelector('.container').style.display = 'block'; + + let userInfo = `Вы вошли как: ${currentUser.name}`; + if (currentUser.auth_type === 'ldap') { + userInfo += ` (LDAP)`; + } + + // Показываем только группы, которые влияют на роль + if (currentUser.groups && currentUser.groups.length > 0) { + // Получаем все группы ролей из конфигурации + const roleGroups = []; + + // Администраторы + if (window.ALLOWED_GROUPS) { + roleGroups.push(...window.ALLOWED_GROUPS.split(',').map(g => g.trim())); + } + + // Секретари + if (window.SECRETARY_GROUPS) { + roleGroups.push(...window.SECRETARY_GROUPS.split(',').map(g => g.trim())); + } + + // Группа помощи + if (window.HELP_GROUPS) { + roleGroups.push(...window.HELP_GROUPS.split(',').map(g => g.trim())); + } + + // IT поддержка + if (window.ITHELP_GROUPS) { + roleGroups.push(...window.ITHELP_GROUPS.split(',').map(g => g.trim())); + } + + // Заявки + if (window.REQUEST_GROUPS) { + roleGroups.push(...window.REQUEST_GROUPS.split(',').map(g => g.trim())); + } + + // Задачи + if (window.TASKS_GROUPS) { + roleGroups.push(...window.TASKS_GROUPS.split(',').map(g => g.trim())); + } + + // Фильтруем группы пользователя, оставляя только те, что влияют на роль + const relevantGroups = currentUser.groups.filter(group => + roleGroups.includes(group) + ); + + // Также всегда показываем роль пользователя + if (currentUser.role) { + userInfo += ` | Роль: ${getRoleDisplayName(currentUser.role)}`; + } + + // Показываем группы только если есть релевантные + if (relevantGroups.length > 0) { + userInfo += ` | Группы ролей: ${relevantGroups.join(', ')}`; + } + } + + document.getElementById('current-user').textContent = userInfo; + + document.getElementById('tasks-controls').style.display = 'block'; + + const showDeletedLabel = document.querySelector('.show-deleted-label'); + if (showDeletedLabel) { + if (currentUser.role === 'admin') { + showDeletedLabel.style.display = 'flex'; + } else { + showDeletedLabel.style.display = 'none'; + } + } + + loadUsers(); + loadTasks(); + loadActivityLogs(); + showSection('tasks'); + + showingTasksWithoutDate = false; + const btn = document.getElementById('tasks-no-date-btn'); + if (btn) btn.classList.remove('active'); +} + +// Вспомогательная функция для отображения понятного имени роли +function getRoleDisplayName(role) { + const roleNames = { + 'admin': 'Администратор', + 'secretary': 'Секретарь', + 'help': 'Помощь', + 'ithelp': 'IT поддержка', + 'request': 'Заявки', + 'tasks': 'Задачи', + 'teacher': 'Учитель' + }; + return roleNames[role] || role; +} + +async function login(event) { + event.preventDefault(); + + const login = document.getElementById('login').value; + const password = document.getElementById('password').value; + + try { + const response = await fetch('/api/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ login, password }) + }); + + if (response.ok) { + const data = await response.json(); + currentUser = data.user; + showMainInterface(); + } else { + const error = await response.json(); + alert(error.error || 'Ошибка входа'); + } + } catch (error) { + console.error('Ошибка:', error); + alert('Ошибка подключения к серверу'); + } +} + +async function logout() { + try { + await fetch('/api/logout', { method: 'POST' }); + currentUser = null; + showLoginInterface(); + } catch (error) { + console.error('Ошибка выхода:', error); + } +} \ No newline at end of file diff --git a/public/doc-tasks.js b/public/doc-tasks.js index 6b1b035..e3bd3fa 100644 --- a/public/doc-tasks.js +++ b/public/doc-tasks.js @@ -1,4 +1,4 @@ -// help-tasks.js - Основные операции с заявками +// tasks.js - Основные операции с задачами let tasks = []; let expandedTasks = new Set(); let showingTasksWithoutDate = false; @@ -27,7 +27,7 @@ async function loadTasks() { const response = await fetch(url); tasks = await response.json(); - // Загружаем файлы для всех заявок + // Загружаем файлы для всех задач await Promise.all(tasks.map(async (task) => { try { const filesResponse = await fetch(`/api/tasks/${task.id}/files`); @@ -37,7 +37,7 @@ async function loadTasks() { task.files = []; } } catch (error) { - console.error(`Ошибка загрузки файлов для заявки ${task.id}:`, error); + console.error(`Ошибка загрузки файлов для задачи ${task.id}:`, error); task.files = []; } })); @@ -45,7 +45,7 @@ async function loadTasks() { renderTasks(); } catch (error) { - console.error('Ошибка загрузки заявок:', error); + console.error('Ошибка загрузки задач:', error); } } @@ -59,7 +59,7 @@ function showTasksWithoutDate() { async function loadTasksWithoutDate() { try { const response = await fetch('/api/tasks'); - if (!response.ok) throw new Error('Ошибка загрузки заявок'); + if (!response.ok) throw new Error('Ошибка загрузки задач'); const allTasks = await response.json(); tasks = allTasks.filter(task => { @@ -69,7 +69,7 @@ async function loadTasksWithoutDate() { return hasTaskDueDate && hasAssignmentDueDates; }); - // Загружаем файлы для всех заявок + // Загружаем файлы для всех задач await Promise.all(tasks.map(async (task) => { try { const filesResponse = await fetch(`/api/tasks/${task.id}/files`); @@ -79,27 +79,14 @@ async function loadTasksWithoutDate() { task.files = []; } } catch (error) { - console.error(`Ошибка загрузки файлов для заявки ${task.id}:`, error); + console.error(`Ошибка загрузки файлов для задачи ${task.id}:`, error); task.files = []; } })); renderTasks(); } catch (error) { - console.error('Ошибка загрузки заявок без срока:', error); - } -} - -async function getHelpUsers() { - try { - const response = await fetch('/api/users/group/doc'); - if (response.ok) { - return await response.json(); - } - return []; - } catch (error) { - console.error('Ошибка получения пользователей группы doc:', error); - return []; + console.error('Ошибка загрузки задач без срока:', error); } } @@ -110,7 +97,7 @@ async function createTask(event) { alert('Требуется аутентификация'); return; } - + const formData = new FormData(); formData.append('title', document.getElementById('title').value); formData.append('description', document.getElementById('description').value); @@ -121,25 +108,14 @@ async function createTask(event) { return; } formData.append('dueDate', dueDate); - // --- ПРОВЕРКА ФАЙЛОВ: минимум 1 документ --- - const iffiles = document.getElementById('files').files; - if (iffiles.length === 0) { - alert('Пожалуйста, загрузите хотя бы один документ для согласования.'); + + // Используем selectedUsers вместо прямого доступа к DOM + if (selectedUsers.length === 0) { + alert('Выберите хотя бы одного исполнителя'); return; } - - // Заявка автоматически назначается всем пользователям группы "help" - // Получаем пользователей группы help - const helpUsers = await getHelpUsers(); - - if (helpUsers.length === 0) { - alert('Нет пользователей в группе "doc". Заявка не может быть создана.'); - return; - } - - // Добавляем всех пользователей группы help как исполнителей - helpUsers.forEach(user => { - formData.append('assignedUsers', user.id); + selectedUsers.forEach(userId => { + formData.append('assignedUsers', userId); }); const files = document.getElementById('files').files; @@ -154,24 +130,22 @@ async function createTask(event) { }); if (response.ok) { - alert('Заявка успешно создана и назначена всем пользователям с ролью "Секретарь"!'); + alert('Задача успешно создана!'); document.getElementById('create-task-form').reset(); document.getElementById('file-list').innerHTML = ''; - // Возвращаем на главную с параметром для отображения уведомления - // loadTasks(); - // loadActivityLogs(); - // showSection('tasks'); - // Возвращаем на главную с параметром для отображения уведомления - setTimeout(() => { - window.location.href = '/?task_created=true&type=doc'; - }, 1500); + document.getElementById('user-search').value = ''; + selectedUsers = []; + renderUsersChecklist(); + loadTasks(); + loadActivityLogs(); + showSection('tasks'); } else { const error = await response.json(); - alert(error.error || 'Ошибка создания заявки'); + alert(error.error || 'Ошибка создания задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка создания заявки'); + alert('Ошибка создания задачи'); } } @@ -180,15 +154,15 @@ async function openEditModal(taskId) { const response = await fetch(`/api/tasks/${taskId}`); if (!response.ok) { if (response.status === 404) { - alert('Заявка не найдена или у вас нет прав доступа'); + alert('Задача не найдена или у вас нет прав доступа'); } - throw new Error('Ошибка загрузки заявки'); + throw new Error('Ошибка загрузки задачи'); } const task = await response.json(); if (!canUserEditTask(task)) { - alert('У вас нет прав для редактирования этой заявки'); + alert('У вас нет прав для редактирования этой задачи'); return; } @@ -198,8 +172,9 @@ async function openEditModal(taskId) { document.getElementById('edit-due-date').value = task.due_date ? formatDateTimeForInput(task.due_date) : ''; - // Показываем пользователей группы help, назначенных на заявку - showHelpGroupUsersInEditModal(task); + // Устанавливаем выбранных пользователей + editSelectedUsers = task.assignments ? task.assignments.map(a => a.user_id) : []; + renderEditUsersChecklist(users); // Показываем существующие файлы currentEditTaskFiles = task.files || []; @@ -208,38 +183,17 @@ async function openEditModal(taskId) { document.getElementById('edit-task-modal').style.display = 'block'; } catch (error) { console.error('Ошибка:', error); - alert('Ошибка загрузки заявки'); + alert('Ошибка загрузки задачи'); } } -function showHelpGroupUsersInEditModal(task) { - const container = document.getElementById('edit-help-group-users'); - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - - if (helpUsers.length === 0) { - container.innerHTML = '

Нет пользователей в группе "doc"

'; - return; - } - - // Получаем назначенных пользователей - const assignedUserIds = task.assignments ? task.assignments.map(a => a.user_id) : []; - - container.innerHTML = helpUsers.map(user => { - const isAssigned = assignedUserIds.includes(user.id.toString()); - return ` -
- - ${user.name} (${user.email}) - ${isAssigned ? 'назначен' : ''} -
- `; - }).join(''); -} - function closeEditModal() { document.getElementById('edit-task-modal').style.display = 'none'; document.getElementById('edit-file-list').innerHTML = ''; + document.getElementById('edit-user-search').value = ''; + editSelectedUsers = []; currentEditTaskFiles = []; + filterEditUsers(); } async function updateTask(event) { @@ -255,14 +209,8 @@ async function updateTask(event) { return; } - // Заявка автоматически назначается всем пользователям группы "help" - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - const assignedUserIds = helpUsers.map(user => user.id); - - if (assignedUserIds.length === 0) { - alert('Нет пользователей в группе "help". Заявка не может быть обновлена.'); - return; - } + // Используем editSelectedUsers + const assignedUserIds = editSelectedUsers; const formData = new FormData(); formData.append('title', title); @@ -282,17 +230,17 @@ async function updateTask(event) { }); if (response.ok) { - alert('Заявка успешно обновлена и назначена всем пользователям группы "doc"!'); + alert('Задача успешно обновлена!'); closeEditModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка обновления заявки'); + alert(error.error || 'Ошибка обновления задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка обновления заявки'); + alert('Ошибка обновления задачи'); } } @@ -304,11 +252,18 @@ function openCopyModal(taskId) { defaultDate.setDate(defaultDate.getDate() + 7); document.getElementById('copy-due-date').value = defaultDate.toISOString().substring(0, 16); + // Сбрасываем выбранных пользователей + copySelectedUsers = []; + renderCopyUsersChecklist(users); + document.getElementById('copy-task-modal').style.display = 'block'; } function closeCopyModal() { document.getElementById('copy-task-modal').style.display = 'none'; + document.getElementById('copy-user-search').value = ''; + copySelectedUsers = []; + filterCopyUsers(); } async function copyTask(event) { @@ -318,16 +273,15 @@ async function copyTask(event) { const dueDate = document.getElementById('copy-due-date').value; if (!dueDate) { - alert('Дата и время выполнения обязательны для копии заявки'); + alert('Дата и время выполнения обязательны для копии задачи'); return; } - // Копия заявки автоматически назначается всем пользователям группы "help" - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - const assignedUserIds = helpUsers.map(user => user.id); + // Используем copySelectedUsers + const assignedUserIds = copySelectedUsers; if (assignedUserIds.length === 0) { - alert('Нет пользователей в группе "doc". Копия заявки не может быть создана.'); + alert('Выберите хотя бы одного исполнителя для копии задачи'); return; } @@ -344,22 +298,22 @@ async function copyTask(event) { }); if (response.ok) { - alert('Копия заявки успешно создана и назначена всем пользователям группы "doc"!'); + alert('Копия задачи успешно создана!'); closeCopyModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка создания копии заявки'); + alert(error.error || 'Ошибка создания копии задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка создания копии заявки'); + alert('Ошибка создания копии задачи'); } } async function closeTask(taskId) { - if (!confirm('Вы уверены, что хотите закрыть эту заявку? Исполнители больше не будут видеть ее.')) { + if (!confirm('Вы уверены, что хотите закрыть эту задачу? Исполнители больше не будут видеть её.')) { return; } @@ -369,16 +323,16 @@ async function closeTask(taskId) { }); if (response.ok) { - alert('Заявка закрыта!'); + alert('Задача закрыта!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка закрытия заявки'); + alert(error.error || 'Ошибка закрытия задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка закрытия заявки'); + alert('Ошибка закрытия задачи'); } } @@ -389,21 +343,21 @@ async function reopenTask(taskId) { }); if (response.ok) { - alert('Заявка открыта!'); + alert('Задача открыта!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка открытия заявки'); + alert(error.error || 'Ошибка открытия задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка открытия заявки'); + alert('Ошибка открытия задачи'); } } async function deleteTask(taskId) { - if (!confirm('Вы уверены, что хотите удалить эту заявку?')) { + if (!confirm('Вы уверены, что хотите удалить эту задачу?')) { return; } @@ -413,16 +367,16 @@ async function deleteTask(taskId) { }); if (response.ok) { - alert('Заявка удалена!'); + alert('Задача удалена!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка удаления заявки'); + alert(error.error || 'Ошибка удаления задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка удаления заявки'); + alert('Ошибка удаления задачи'); } } @@ -433,16 +387,16 @@ async function restoreTask(taskId) { }); if (response.ok) { - alert('Заявка восстановлена!'); + alert('Задача восстановлена!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка восстановления заявки'); + alert(error.error || 'Ошибка восстановления задачи'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка восстановления заявки'); + alert('Ошибка восстановления задачи'); } } @@ -528,17 +482,17 @@ async function sendForRework(event) { }); if (response.ok) { - alert('Заявка возвращена на доработку!'); + alert('Задача возвращена на доработку!'); closeReworkModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); - alert(error.error || 'Ошибка возврата заявки на доработку'); + alert(error.error || 'Ошибка возврата задачи на доработку'); } } catch (error) { console.error('Ошибка:', error); - alert('Ошибка возврата заявки на доработку'); + alert('Ошибка возврата задачи на доработку'); } } @@ -571,43 +525,34 @@ function canUserEditTask(task) { // Администратор может всё if (currentUser.role === 'admin') return true; - // Создатель может редактировать свою заявку + // Создатель может редактировать свою задачу if (parseInt(task.created_by) === currentUser.id) { - // Но если заявка уже назначена группе "help", + // Но если задача уже назначена другим пользователям, // создатель может только просматривать if (task.assignments && task.assignments.length > 0) { - return false; + // Проверяем, назначена ли задача другим пользователям (не только себе) + const assignedToOthers = task.assignments.some(assignment => + parseInt(assignment.user_id) !== currentUser.id + ); + + if (assignedToOthers) { + // Создатель может только просматривать и закрывать задачу + return false; + } } return true; } - // Пользователи группы "help" могут менять только свой статус + // Исполнитель может менять только свой статус if (task.assignments) { - const isHelpUser = task.assignments.some(assignment => + const isExecutor = task.assignments.some(assignment => parseInt(assignment.user_id) === currentUser.id ); - if (isHelpUser) { - return false; // Могут менять только статус + if (isExecutor) { + // Исполнитель может менять только статус + return false; } } return false; -} - -// Функция для отображения пользователей группы help при создании заявки -function showHelpGroupUsers() { - const container = document.getElementById('help-group-users'); - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - - if (helpUsers.length === 0) { - container.innerHTML = '

Нет пользователей в группе "help"

'; - return; - } - - container.innerHTML = helpUsers.map(user => ` -
- - ${user.name} (${user.email}) -
- `).join(''); } \ No newline at end of file diff --git a/public/doc-users.js b/public/doc-users.js index 67399dc..61186da 100644 --- a/public/doc-users.js +++ b/public/doc-users.js @@ -1,4 +1,4 @@ -// help-users.js - Управление пользователями +// users.js - Управление пользователями let users = []; let allUsers = []; let filteredUsers = []; @@ -8,126 +8,233 @@ let copySelectedUsers = []; async function loadUsers() { try { - const response = await fetch('/api/users'); - users = await response.json(); - allUsers = users; - - // Получаем пользователей группы "help" - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - filteredUsers = helpUsers; - - // Показываем пользователей группы help при создании заявки - showHelpGroupUsers(); - + const response = await fetch('/api/users'); + const allUsersData = await response.json(); + //users = await response.json(); + // Сохраняем всех пользователей + allUsers = allUsersData; + // Фильтруем пользователей в зависимости от прав текущего пользователя + users = filterAssignableUsers(allUsersData); + filteredUsers = [...users]; + renderUsersChecklist(); + renderEditUsersChecklist(); + renderCopyUsersChecklist(); populateFilterDropdowns(); } catch (error) { console.error('Ошибка загрузки пользователей:', error); } } +function filterAssignableUsers(allUsers) { + if (!currentUser) return []; + + // Администратор видит всех пользователей + if (currentUser.role === 'admin') { + return allUsers.filter(user => user.id !== currentUser.id); + } + if (currentUser.role === 'secretary') { + return allUsers.filter(user => user.id !== currentUser.id); + } + if (currentUser.role === 'ithelp') { + return allUsers.filter(user => + (user.role === 'teacher' || user.role === 'tasks' || user.role === 'help' || user.role === 'request' || user.role === 'ithelp') && + user.id !== currentUser.id + ); + } + if (currentUser.role === 'request') { + return allUsers.filter(user => + (user.role === 'teacher' || user.role === 'tasks' || user.role === 'help' || user.role === 'request' || user.role === 'ithelp') && + user.id !== currentUser.id + ); + } + // tasks видит учителей и других tasks + if (currentUser.role === 'help') { + return allUsers.filter(user => + (user.role === 'teacher' || user.role === 'tasks' || user.role === 'help' || user.role === 'request' || user.role === 'ithelp') && + user.id !== currentUser.id + ); + } + // tasks видит учителей и других tasks + if (currentUser.role === 'tasks') { + return allUsers.filter(user => + (user.role === 'teacher' || user.role === 'tasks' || user.role === 'help' || user.role === 'request' || user.role === 'ithelp') && + user.id !== currentUser.id + ); + } + // Учитель видит только учителей + if (currentUser.role === 'teacher') { + return allUsers.filter(user => + (user.role === 'help' || user.role === 'request' || user.role === 'ithelp') && + 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)]; // Убираем дубликаты +} function populateFilterDropdowns() { const creatorFilter = document.getElementById('creator-filter'); const assigneeFilter = document.getElementById('assignee-filter'); - // Проверяем существование элементов (они есть только на странице help.html) - if (!creatorFilter || !assigneeFilter) { - console.log('Фильтры не найдены (возможно, не на странице help.html)'); - return; - } - creatorFilter.innerHTML = ''; - assigneeFilter.innerHTML = ''; + assigneeFilter.innerHTML = ''; - // Для заказчиков показываем всех пользователей users.forEach(user => { const creatorOption = document.createElement('option'); creatorOption.value = user.id; creatorOption.textContent = `${user.name} (${user.login})`; - creatorFilter.appendChild(creatorOption); - }); - - // Для исполнителей показываем только пользователей группы "help" - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - helpUsers.forEach(user => { - const assigneeOption = document.createElement('option'); - assigneeOption.value = user.id; - assigneeOption.textContent = `${user.name} (${user.login}) - группа "help"`; + creatorFilter.appendChild(creatorOption.cloneNode(true)); + + const assigneeOption = creatorOption.cloneNode(true); assigneeFilter.appendChild(assigneeOption); }); } -// Функция для отображения пользователей группы help -function showHelpGroupUsers() { - const container = document.getElementById('help-group-users'); - - // Проверяем существование элемента (он есть только на странице help.html) - if (!container) { - console.log('Контейнер help-group-users не найден (возможно, не на странице help.html)'); - return; - } - - const helpUsers = users.filter(user => user.groups && user.groups.includes('Секретарь')); - - if (helpUsers.length === 0) { - container.innerHTML = '
Нет пользователей в группе "help"
'; - return; - } - - container.innerHTML = ` -
- Заявка будет автоматически назначена ${helpUsers.length} пользователям группы "help": -
-
- ${helpUsers.map(user => ` -
- - ${user.name} - (${user.email}) -
- `).join('')} -
- `; -} - -// Старые функции фильтрации оставляем, но они теперь не используются для выбора исполнителей function filterUsers() { - const searchInput = document.getElementById('user-search'); - if (!searchInput) return; // Элемент есть только на странице help.html - - const search = searchInput.value.toLowerCase(); - // Фильтруем пользователей группы "help" + const search = document.getElementById('user-search').value.toLowerCase(); filteredUsers = users.filter(user => - user.groups && user.groups.includes('Секретарь') && ( - user.name.toLowerCase().includes(search) || - user.login.toLowerCase().includes(search) || - user.email.toLowerCase().includes(search) - ) + user.name.toLowerCase().includes(search) || + user.login.toLowerCase().includes(search) || + user.email.toLowerCase().includes(search) ); - // Не рендерим чеклист, так как выбираем всех пользователей группы help + renderUsersChecklist(); } function filterEditUsers() { - // Не используется, так как заявка автоматически назначается всем пользователям группы help + 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) + ); + renderEditUsersChecklist(filtered); } function filterCopyUsers() { - // Не используется, так как заявка автоматически назначается всем пользователям группы help + 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) + ); + renderCopyUsersChecklist(filtered); } -// Старые функции рендеринга оставляем для совместимости, но они не будут использоваться function renderUsersChecklist() { - // Не рендерим чеклист, так как выбираем всех пользователей группы help + const container = document.getElementById('users-checklist'); + container.innerHTML = filteredUsers + .filter(user => user.id !== currentUser.id) + .map(user => ` +
+ +
+ `).join(''); } function renderEditUsersChecklist(filtered = users) { - // Не рендерим чеклист, так как заявка автоматически назначается всем пользователям группы help + const container = document.getElementById('edit-users-checklist'); + container.innerHTML = filtered + .filter(user => user.id !== currentUser.id) + .map(user => ` +
+ +
+ `).join(''); } function renderCopyUsersChecklist(filtered = users) { - // Не рендерим чеклист, так как заявка автоматически назначается всем пользователям группы help + const container = document.getElementById('copy-users-checklist'); + container.innerHTML = filtered + .filter(user => user.id !== currentUser.id) + .map(user => ` +
+ +
+ `).join(''); } -// Старые функции выбора пользователей оставляем для совместимости function toggleUserSelection(checkbox, userId) { if (checkbox.checked) { selectedUsers.push(userId); diff --git a/public/doc.html b/public/doc.html index 62a832e..4757945 100644 --- a/public/doc.html +++ b/public/doc.html @@ -3,77 +3,140 @@ - Согласование документов + School CRM - Управление задачами - -
+ + +
-

Согласование документов

+

School CRM - Согласование документов

-
- -
-

Создать новый документ

-
-
-
- - +
+

Все задачи

+
+
+
+ +
- -
- - + + + + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+

Создать новую задачу

+ +
+ +
- +
- -
-
- - + +
+ + +
+ +
+ + +
- +
- - -
- -
- +
- -
-

Документ будет отправлен на согласование секретарю

-
- +
- - -
-
-

Мои документы

-
-
- - -
-
- - -
-
-
-
-
Загрузка документов...
-
-
- - -
-
-

Документы на согласование

-
-
- - -
-
-
-
-
Загрузка документов...
-
+ +
+

Лог активности

+
+
- - -