цвета
This commit is contained in:
597
public/help-tasks.js
Normal file
597
public/help-tasks.js
Normal file
@@ -0,0 +1,597 @@
|
||||
// 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 = '<p class="no-users">Нет пользователей в группе "help"</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 = '';
|
||||
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 => `
|
||||
<div class="help-user-item">
|
||||
<i class="fas fa-user"></i>
|
||||
<span>${user.name} (${user.email})</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
Reference in New Issue
Block a user