${!isDeleted && !isClosed ? `
+ ${canEdit ? `
` : ''}
${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;
}