From 77504d9130c7ac982a6f24e3bb97ee38b0954d7a Mon Sep 17 00:00:00 2001 From: kalugin66 Date: Mon, 2 Feb 2026 22:04:38 +0500 Subject: [PATCH] task-file --- public/index.html | 12 +-- public/style.css | 1 - public/tasks.js | 22 +++++- public/ui.js | 190 +++++++++++++++++++++++++++++++++++++++++++--- task-endpoints.js | 11 ++- 5 files changed, 219 insertions(+), 17 deletions(-) diff --git a/public/index.html b/public/index.html index e93cdc3..70055a3 100644 --- a/public/index.html +++ b/public/index.html @@ -258,8 +258,10 @@
- - + + + +
- +
` : ''} ${canEdit ? `` : ''} ${canEdit ? `` : ''} @@ -246,7 +247,7 @@ function renderAssignment(assignment, taskId, canEdit) { ${assignment.start_date || assignment.due_date ? `
${assignment.start_date ? `Начало: ${formatDateTime(assignment.start_date)}` : ''} - ${assignment.due_date ? `2Выполнить до: ${formatDateTime(assignment.due_date)}` : ''} + ${assignment.due_date ? `Выполнить до: ${formatDateTime(assignment.due_date)}` : ''}
` : ''} ${assignment.rework_comment ? ` @@ -363,15 +364,8 @@ function getUserRoleInTask(task) { if (currentUser.role === 'admin') return 'Администратор'; + // Создатель задачи всегда должен иметь право редактировать свою задачу 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 'Создатель (только просмотр)'; - } - } return 'Создатель'; } @@ -468,4 +462,182 @@ async function viewTaskDetails(taskId) { } catch (error) { console.error('Ошибка загрузки деталей задачи:', error); } +} + +// Функция для открытия модального окна добавления файла +function openAddFileModal(taskId) { + // Находим задачу + const task = tasks.find(t => t.id === taskId); + if (!task) { + alert('Задача не найдена'); + return; + } + + // Проверяем права + if (!canUserAddFilesToTask(task)) { + alert('У вас нет прав для добавления файлов к этой задаче'); + return; + } + + // Создаем модальное окно + const modalHtml = ` + + `; + + // Добавляем модальное окно в DOM + const modalContainer = document.createElement('div'); + modalContainer.innerHTML = modalHtml; + document.body.appendChild(modalContainer); + + // Обработчик отправки формы + document.getElementById('add-file-form').addEventListener('submit', async function(e) { + e.preventDefault(); + + const fileInput = document.getElementById('file-input'); + const description = document.getElementById('file-description').value; + + if (fileInput.files.length === 0) { + alert('Выберите файл для загрузки'); + return; + } + + const file = fileInput.files[0]; + const formData = new FormData(); + + // Пробуем сначала 'files', затем 'file' + formData.append('files', file); // Или 'file' в зависимости от сервера + formData.append('task_id', taskId); + if (description) { + formData.append('description', description); + } + + try { + // Попробуем с полем 'files' (скорее всего это правильное имя) + let response = await fetch(`/api/tasks/${taskId}/files`, { + method: 'POST', + body: formData + }); + + if (!response.ok) { + // Попробуем с полем 'file' + console.log('Попытка с именем поля "file"...'); + formData.delete('files'); + formData.append('file', file); + + response = await fetch(`/api/tasks/${taskId}/files`, { + method: 'POST', + body: formData + }); + } + + if (response.ok) { + alert('Файл успешно добавлен'); + await loadTaskFiles(taskId); + closeAddFileModal(); + + // Обновляем задачу, если она развернута + if (expandedTasks.has(taskId)) { + renderTasks(); + } + } else { + const errorText = await response.text(); + console.error('Ошибка сервера:', errorText); + alert(`Ошибка при добавлении файла: ${response.status} ${response.statusText}`); + } + } catch (error) { + console.error('Ошибка:', error); + alert('Сетевая ошибка при добавлении файла: ' + error.message); + } + }); + + // Показываем модальное окно + setTimeout(() => { + document.getElementById('add-file-modal').style.display = 'block'; + }, 10); +} + +// Функция для закрытия модального окна добавления файла +function closeAddFileModal() { + const modal = document.getElementById('add-file-modal'); + if (modal) { + modal.style.display = 'none'; + // Удаляем модальное окно из DOM через некоторое время + setTimeout(() => { + modal.parentElement.remove(); + }, 300); + } +} + +// Функция для закрытия модального окна добавления файла +function closeAddFileModal() { + const modal = document.getElementById('add-file-modal'); + if (modal) { + modal.style.display = 'none'; + // Удаляем модальное окно из DOM через некоторое время + setTimeout(() => { + modal.parentElement.remove(); + }, 300); + } +} + +// Функция для загрузки файлов задачи (если её еще нет) +async function loadTaskFiles(taskId) { + try { + const response = await fetch(`/api/tasks/${taskId}/files`); + const files = await response.json(); + + // Обновляем файлы в задаче + const taskIndex = tasks.findIndex(t => t.id === taskId); + if (taskIndex !== -1) { + tasks[taskIndex].files = files; + } + + // Обновляем отображение файлов + const fileContainer = document.getElementById(`files-${taskId}`); + if (fileContainer) { + const fileList = fileContainer.querySelector('.file-icons-container'); + if (fileList) { + fileList.innerHTML = files.map(file => renderFileIcon(file)).join(''); + } else { + fileContainer.innerHTML = ` + Файлы: + ${files.length > 0 ? + `
${files.map(file => renderFileIcon(file)).join('')}
` : + 'нет файлов' + } + `; + } + } + } catch (error) { + console.error('Ошибка загрузки файлов:', error); + } } \ No newline at end of file diff --git a/task-endpoints.js b/task-endpoints.js index 5281bd2..4356801 100644 --- a/task-endpoints.js +++ b/task-endpoints.js @@ -48,7 +48,16 @@ function setupTaskEndpoints(app, db, upload) { } return true; } - + // Исполнитель может загружать файлы в свою задачу + // Проверяем, назначен ли пользователь на эту задачу + if (task.assignments && task.assignments.length > 0) { + const isAssigned = task.assignments.some(assignment => + parseInt(assignment.user_id) === user.id + ); + if (isAssigned) { + return true; // Исполнитель может загружать файлы + } + } return false; }