Files
minicrm/public/doc-tasks.js
2026-01-29 17:08:15 +05:00

613 lines
22 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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/doc');
if (response.ok) {
return await response.json();
}
return [];
} catch (error) {
console.error('Ошибка получения пользователей группы doc:', 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);
// --- ПРОВЕРКА ФАЙЛОВ: минимум 1 документ ---
const iffiles = document.getElementById('files').files;
if (iffiles.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);
});
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('Заявка успешно создана и назначена всем пользователям с ролью "Секретарь"!');
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);
} 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('Секретарь'));
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 = '';
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('Секретарь'));
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('Заявка успешно обновлена и назначена всем пользователям группы "doc"!');
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('Секретарь'));
const assignedUserIds = helpUsers.map(user => user.id);
if (assignedUserIds.length === 0) {
alert('Нет пользователей в группе "doc". Копия заявки не может быть создана.');
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('Копия заявки успешно создана и назначена всем пользователям группы "doc"!');
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('Секретарь'));
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('');
}