This commit is contained in:
2026-02-02 16:16:14 +05:00
parent cd827b0e9a
commit 0b54ca8404
11 changed files with 1185 additions and 1020 deletions

View File

@@ -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 = '<p class="no-users">Нет пользователей в группе "doc"</p>';
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 `
<div class="help-user-item ${isAssigned ? 'assigned' : 'not-assigned'}">
<i class="fas ${isAssigned ? 'fa-user-check' : 'fa-user'}"></i>
<span>${user.name} (${user.email})</span>
${isAssigned ? '<span class="assigned-badge">назначен</span>' : ''}
</div>
`;
}).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 = '<p class="no-users">Нет пользователей в группе "help"</p>';
return;
}
container.innerHTML = helpUsers.map(user => `
<div class="help-user-item">
<i class="fas fa-user"></i>
<span>${user.name} (${user.email})</span>
</div>
`).join('');
}