// help-tasks.js - Основные операции с заявками let tasks = []; let expandedTasks = new Set(); let showingTasksWithoutDate = false; async function loadTasks() { try { showingTasksWithoutDate = false; const btn = document.getElementById('tasks-no-date-btn'); if (btn) btn.classList.remove('active'); const search = document.getElementById('search-tasks')?.value || ''; const statusFilter = document.getElementById('status-filter')?.value || 'active,in_progress,assigned,overdue,rework'; const creatorFilter = document.getElementById('creator-filter')?.value || ''; const assigneeFilter = document.getElementById('assignee-filter')?.value || ''; const deadlineFilter = document.getElementById('deadline-filter')?.value || ''; const showDeleted = document.getElementById('show-deleted')?.checked || false; let url = '/api/tasks?'; if (search) url += `search=${encodeURIComponent(search)}&`; if (statusFilter) url += `status=${encodeURIComponent(statusFilter)}&`; if (creatorFilter) url += `creator=${encodeURIComponent(creatorFilter)}&`; if (assigneeFilter) url += `assignee=${encodeURIComponent(assigneeFilter)}&`; if (deadlineFilter) url += `deadline=${encodeURIComponent(deadlineFilter)}&`; if (showDeleted) url += `showDeleted=true&`; 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`); if (filesResponse.ok) { task.files = await filesResponse.json(); } else { task.files = []; } } catch (error) { console.error(`Ошибка загрузки файлов для заявки ${task.id}:`, error); task.files = []; } })); renderTasks(); } catch (error) { console.error('Ошибка загрузки заявок:', error); } } function showTasksWithoutDate() { showingTasksWithoutDate = true; const btn = document.getElementById('tasks-no-date-btn'); if (btn) btn.classList.add('active'); loadTasksWithoutDate(); } async function loadTasksWithoutDate() { try { const response = await fetch('/api/tasks'); if (!response.ok) throw new Error('Ошибка загрузки заявок'); const allTasks = await response.json(); tasks = allTasks.filter(task => { const hasTaskDueDate = !task.due_date; const hasAssignmentDueDates = task.assignments && task.assignments.every(assignment => !assignment.due_date); return hasTaskDueDate && hasAssignmentDueDates; }); // Загружаем файлы для всех заявок await Promise.all(tasks.map(async (task) => { try { const filesResponse = await fetch(`/api/tasks/${task.id}/files`); if (filesResponse.ok) { task.files = await filesResponse.json(); } else { task.files = []; } } catch (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/help'); if (response.ok) { return await response.json(); } return []; } catch (error) { console.error('Ошибка получения пользователей группы help:', error); return []; } } async function createTask(event) { event.preventDefault(); if (!currentUser) { alert('Требуется аутентификация'); return; } const formData = new FormData(); formData.append('title', document.getElementById('title').value); formData.append('description', document.getElementById('description').value); const dueDate = document.getElementById('due-date').value; if (!dueDate) { alert('Дата и время выполнения обязательны'); return; } formData.append('dueDate', dueDate); // Заявка автоматически назначается всем пользователям группы "help" // Получаем пользователей группы help const helpUsers = await getHelpUsers(); if (helpUsers.length === 0) { alert('Нет пользователей в группе "help". Заявка не может быть создана.'); return; } // Добавляем всех пользователей группы help как исполнителей helpUsers.forEach(user => { formData.append('assignedUsers', user.id); }); const files = document.getElementById('files').files; for (let i = 0; i < files.length; i++) { formData.append('files', files[i]); } try { const response = await fetch('/api/tasks', { method: 'POST', body: formData }); if (response.ok) { alert('Заявка успешно создана и назначена всем пользователям группы "help"!'); document.getElementById('create-task-form').reset(); document.getElementById('file-list').innerHTML = ''; loadTasks(); loadActivityLogs(); showSection('tasks'); } else { const error = await response.json(); alert(error.error || 'Ошибка создания заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка создания заявки'); } } async function openEditModal(taskId) { try { const response = await fetch(`/api/tasks/${taskId}`); if (!response.ok) { if (response.status === 404) { alert('Заявка не найдена или у вас нет прав доступа'); } throw new Error('Ошибка загрузки заявки'); } const task = await response.json(); if (!canUserEditTask(task)) { alert('У вас нет прав для редактирования этой заявки'); return; } document.getElementById('edit-task-id').value = task.id; document.getElementById('edit-title').value = task.title; document.getElementById('edit-description').value = task.description || ''; document.getElementById('edit-due-date').value = task.due_date ? formatDateTimeForInput(task.due_date) : ''; // Показываем пользователей группы help, назначенных на заявку showHelpGroupUsersInEditModal(task); // Показываем существующие файлы currentEditTaskFiles = task.files || []; updateEditFileList(); document.getElementById('edit-task-modal').style.display = 'block'; } catch (error) { console.error('Ошибка:', error); alert('Ошибка загрузки заявки'); } } function showHelpGroupUsersInEditModal(task) { const container = document.getElementById('edit-help-group-users'); const helpUsers = users.filter(user => user.groups && user.groups.includes('help')); if (helpUsers.length === 0) { container.innerHTML = '

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

'; 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 = ''; currentEditTaskFiles = []; } async function updateTask(event) { event.preventDefault(); const taskId = document.getElementById('edit-task-id').value; const title = document.getElementById('edit-title').value; const description = document.getElementById('edit-description').value; const dueDate = document.getElementById('edit-due-date').value; if (!dueDate) { alert('Дата и время выполнения обязательны'); return; } // Заявка автоматически назначается всем пользователям группы "help" const helpUsers = users.filter(user => user.groups && user.groups.includes('help')); const assignedUserIds = helpUsers.map(user => user.id); if (assignedUserIds.length === 0) { alert('Нет пользователей в группе "help". Заявка не может быть обновлена.'); return; } const formData = new FormData(); formData.append('title', title); formData.append('description', description); formData.append('assignedUsers', JSON.stringify(assignedUserIds)); formData.append('dueDate', dueDate); const files = document.getElementById('edit-files').files; for (let i = 0; i < files.length; i++) { formData.append('files', files[i]); } try { const response = await fetch(`/api/tasks/${taskId}`, { method: 'PUT', body: formData }); if (response.ok) { alert('Заявка успешно обновлена и назначена всем пользователям группы "help"!'); closeEditModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка обновления заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка обновления заявки'); } } function openCopyModal(taskId) { document.getElementById('copy-task-id').value = taskId; // Устанавливаем дату по умолчанию (через 7 дней) const defaultDate = new Date(); defaultDate.setDate(defaultDate.getDate() + 7); document.getElementById('copy-due-date').value = defaultDate.toISOString().substring(0, 16); document.getElementById('copy-task-modal').style.display = 'block'; } function closeCopyModal() { document.getElementById('copy-task-modal').style.display = 'none'; } async function copyTask(event) { event.preventDefault(); const taskId = document.getElementById('copy-task-id').value; const dueDate = document.getElementById('copy-due-date').value; if (!dueDate) { alert('Дата и время выполнения обязательны для копии заявки'); return; } // Копия заявки автоматически назначается всем пользователям группы "help" const helpUsers = users.filter(user => user.groups && user.groups.includes('help')); const assignedUserIds = helpUsers.map(user => user.id); if (assignedUserIds.length === 0) { alert('Нет пользователей в группе "help". Копия заявки не может быть создана.'); return; } try { const response = await fetch(`/api/tasks/${taskId}/copy`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ assignedUsers: assignedUserIds, dueDate: dueDate }) }); if (response.ok) { alert('Копия заявки успешно создана и назначена всем пользователям группы "help"!'); closeCopyModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка создания копии заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка создания копии заявки'); } } async function closeTask(taskId) { if (!confirm('Вы уверены, что хотите закрыть эту заявку? Исполнители больше не будут видеть ее.')) { return; } try { const response = await fetch(`/api/tasks/${taskId}/close`, { method: 'POST' }); if (response.ok) { alert('Заявка закрыта!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка закрытия заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка закрытия заявки'); } } async function reopenTask(taskId) { try { const response = await fetch(`/api/tasks/${taskId}/reopen`, { method: 'POST' }); if (response.ok) { alert('Заявка открыта!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка открытия заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка открытия заявки'); } } async function deleteTask(taskId) { if (!confirm('Вы уверены, что хотите удалить эту заявку?')) { return; } try { const response = await fetch(`/api/tasks/${taskId}`, { method: 'DELETE' }); if (response.ok) { alert('Заявка удалена!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка удаления заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка удаления заявки'); } } async function restoreTask(taskId) { try { const response = await fetch(`/api/tasks/${taskId}/restore`, { method: 'POST' }); if (response.ok) { alert('Заявка восстановлена!'); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка восстановления заявки'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка восстановления заявки'); } } function openEditAssignmentModal(taskId, userId) { const task = tasks.find(t => t.id === taskId); if (!task) return; const assignment = task.assignments.find(a => a.user_id === userId); if (!assignment) return; document.getElementById('edit-assignment-task-id').value = taskId; document.getElementById('edit-assignment-user-id').value = userId; document.getElementById('edit-assignment-due-date').value = assignment.due_date ? formatDateTimeForInput(assignment.due_date) : ''; document.getElementById('edit-assignment-modal').style.display = 'block'; } function closeEditAssignmentModal() { document.getElementById('edit-assignment-modal').style.display = 'none'; } async function updateAssignment(event) { event.preventDefault(); const taskId = document.getElementById('edit-assignment-task-id').value; const userId = document.getElementById('edit-assignment-user-id').value; const dueDate = document.getElementById('edit-assignment-due-date').value; if (!dueDate) { alert('Дата и время выполнения обязательны'); return; } try { const response = await fetch(`/api/tasks/${taskId}/assignment/${userId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ dueDate: dueDate }) }); if (response.ok) { alert('Сроки исполнителя обновлены!'); closeEditAssignmentModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка обновления сроков'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка обновления сроков'); } } function openReworkModal(taskId) { document.getElementById('rework-task-id').value = taskId; document.getElementById('rework-task-modal').style.display = 'block'; } function closeReworkModal() { document.getElementById('rework-task-modal').style.display = 'none'; document.getElementById('rework-comment').value = ''; } async function sendForRework(event) { event.preventDefault(); const taskId = document.getElementById('rework-task-id').value; const comment = document.getElementById('rework-comment').value; try { const response = await fetch(`/api/tasks/${taskId}/rework`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ comment }) }); if (response.ok) { alert('Заявка возвращена на доработку!'); closeReworkModal(); loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка возврата заявки на доработку'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка возврата заявки на доработку'); } } async function updateStatus(taskId, userId, status) { try { const response = await fetch(`/api/tasks/${taskId}/status`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ userId, status }) }); if (response.ok) { loadTasks(); loadActivityLogs(); } else { const error = await response.json(); alert(error.error || 'Ошибка обновления статуса'); } } catch (error) { console.error('Ошибка:', error); alert('Ошибка обновления статуса'); } } function canUserEditTask(task) { if (!currentUser) return false; // Администратор может всё if (currentUser.role === 'admin') return true; // Создатель может редактировать свою заявку if (parseInt(task.created_by) === currentUser.id) { // Но если заявка уже назначена группе "help", // создатель может только просматривать if (task.assignments && task.assignments.length > 0) { return false; } return true; } // Пользователи группы "help" могут менять только свой статус if (task.assignments) { const isHelpUser = task.assignments.some(assignment => parseInt(assignment.user_id) === currentUser.id ); if (isHelpUser) { return false; // Могут менять только статус } } return false; } // Функция для отображения пользователей группы help при создании заявки function showHelpGroupUsers() { const container = document.getElementById('help-group-users'); const helpUsers = users.filter(user => user.groups && user.groups.includes('help')); container.innerHTML = helpUsers.map(user => `
${user.name} (${user.email})
`).join(''); }