// tasks.js - Основные операции с задачами
let tasks = [];
let expandedTasks = new Set();
let showingTasksWithoutDate = false;
async function loadTasks() {
try {
// Получаем значения фильтров
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 searchQuery = document.getElementById('search-tasks')?.value || '';
const typeFilter = document.getElementById('type-filter')?.value || '';
// Формируем URL с параметрами
let url = '/api/tasks?';
const params = [];
if (statusFilter !== 'all') {
params.push(`status=${encodeURIComponent(statusFilter)}`);
}
if (creatorFilter) {
params.push(`creator=${encodeURIComponent(creatorFilter)}`);
}
if (assigneeFilter) {
params.push(`assignee=${encodeURIComponent(assigneeFilter)}`);
}
if (deadlineFilter) {
params.push(`deadline=${encodeURIComponent(deadlineFilter)}`);
}
if (searchQuery) {
params.push(`search=${encodeURIComponent(searchQuery)}`);
}
if (typeFilter) {
params.push(`task_type=${encodeURIComponent(typeFilter)}`);
}
url += params.join('&');
console.log('Загрузка задач с фильтрами:', url);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
tasks = await response.json();
console.log(`Загружено ${tasks.length} задач`);
// Загружаем поля документа для задач типа "document"
await loadDocumentFieldsForTasks();
// Загружаем файлы для развернутых задач
await loadFilesForExpandedTasks();
// Обновляем отображение
const activeSection = document.querySelector('.section.active');
if (activeSection) {
const sectionId = activeSection.id;
if (sectionId === 'mytasks-section') {
filterMyTasks();
} else if (sectionId === 'runtasks-section') {
filterRunTasks();
} else {
renderTasks();
}
} else {
renderTasks();
}
} catch (error) {
console.error('Ошибка загрузки задач:', error);
const container = document.getElementById('tasks-list');
if (container) {
container.innerHTML = '
Ошибка загрузки задач
';
}
}
}
// Новая функция для загрузки полей документов
async function loadDocumentFieldsForTasks() {
const documentTasks = tasks.filter(task => task.task_type === 'document');
if (documentTasks.length === 0) {
return;
}
console.log(`Загрузка полей документов для ${documentTasks.length} задач`);
// Загружаем поля для каждой задачи
for (const task of documentTasks) {
try {
const docResponse = await fetch(`/api/tasks/${task.id}/document-fields`);
if (docResponse.ok) {
const docData = await docResponse.json();
task.document_fields = docData.data || {};
console.log(`✅ Загружены поля для задачи ${task.id}:`, task.document_fields);
} else {
task.document_fields = {};
}
} catch (error) {
console.error(`Ошибка загрузки полей документа для задачи ${task.id}:`, error);
task.document_fields = {};
}
}
}
// Новая функция для загрузки файлов развернутых задач
async function loadFilesForExpandedTasks() {
const expandedTasksArray = tasks.filter(task => expandedTasks.has(task.id));
if (expandedTasksArray.length === 0) {
return;
}
await Promise.all(expandedTasksArray.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 = [];
}
}));
}
function showTasksWithoutDate() {
showingTasksWithoutDate = true;
const btn = document.getElementById('tasks-no-date-btn');
if (btn) btn.classList.add('active');
loadTasksWithoutDate();
}
function resetAllFilters() {
document.getElementById('status-filter').value = 'active,in_progress,assigned,overdue,rework';
document.getElementById('creator-filter').value = '';
document.getElementById('assignee-filter').value = '';
document.getElementById('deadline-filter').value = '';
document.getElementById('type-filter').value = '';
document.getElementById('search-tasks').value = '';
loadTasks();
}
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 = [];
}
}));
// Загружаем поля документов
await loadDocumentFieldsForTasks();
renderTasks();
} catch (error) {
console.error('Ошибка загрузки задач без срока:', error);
}
}
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) : '';
// Устанавливаем выбранных пользователей
editSelectedUsers = task.assignments ? task.assignments.map(a => a.user_id) : [];
renderEditUsersChecklist(users);
// Показываем существующие файлы
currentEditTaskFiles = task.files || [];
updateEditFileList();
document.getElementById('edit-task-modal').style.display = 'block';
} catch (error) {
console.error('Ошибка:', error);
alert('Ошибка загрузки задачи');
}
}
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) {
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;
}
const assignedUserIds = editSelectedUsers;
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('Задача успешно обновлена!');
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;
const defaultDate = new Date();
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) {
event.preventDefault();
const taskId = document.getElementById('copy-task-id').value;
const dueDate = document.getElementById('copy-due-date').value;
if (!dueDate) {
alert('Дата и время выполнения обязательны для копии задачи');
return;
}
const assignedUserIds = copySelectedUsers;
if (assignedUserIds.length === 0) {
alert('Выберите хотя бы одного исполнителя для копии задачи');
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('Копия задачи успешно создана!');
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 (currentUser.role === 'tasks') return true;
if (parseInt(task.created_by) === currentUser.id) {
if (task.assignments && task.assignments.length > 0) {
const assignedToOthers = task.assignments.some(assignment =>
parseInt(assignment.user_id) !== currentUser.id
);
if (assignedToOthers) {
return true;
}
}
return true;
}
if (task.assignments) {
const isExecutor = task.assignments.some(assignment =>
parseInt(assignment.user_id) === currentUser.id
);
if (isExecutor) {
return false;
}
}
return false;
}
function canUserAddFilesToTask(task) {
if (!currentUser) return false;
if (currentUser.role === 'admin') return true;
if (parseInt(task.created_by) === currentUser.id) return true;
if (task.assignments) {
const isExecutor = task.assignments.some(assignment =>
parseInt(assignment.user_id) === currentUser.id
);
return isExecutor;
}
return false;
}
// Добавляем отладочную функцию
function debugDocumentFields() {
console.log('=== ОТЛАДКА ПОЛЕЙ ДОКУМЕНТОВ ===');
const documentTasks = tasks.filter(task => task.task_type === 'document');
console.log(`Найдено ${documentTasks.length} задач типа "document"`);
documentTasks.forEach(task => {
console.log(`Задача ${task.id}:`, {
title: task.title,
document_fields: task.document_fields || 'НЕТ ПОЛЕЙ'
});
});
console.log('================================');
}
// Вызываем отладку после загрузки (можно вызвать вручную из консоли)
window.debugDocumentFields = debugDocumentFields;