Files
minicrm/public/main.js
2026-02-18 18:35:01 +05:00

502 lines
21 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.
// main.js - Главный файл инициализации
let currentTaskView = 'all'; // 'all', 'my_assigned', 'assigned_to_me'
let allTasksCache = []; // Кэш всех задач
document.addEventListener('DOMContentLoaded', function() {
checkAuth();
setupEventListeners();
// Инициализация выбора времени
initializeTimeSelectors();
// Инициализация фильтра
const taskViewFilter = document.getElementById('task-view-filter');
if (taskViewFilter) {
taskViewFilter.value = currentTaskView;
}
// По умолчанию показываем секцию задач
showSection('tasks');
});
function setupEventListeners() {
// Форма входа
document.getElementById('login-form').addEventListener('submit', login);
// Формы задач
document.getElementById('create-task-form').addEventListener('submit', createTask);
document.getElementById('edit-task-form').addEventListener('submit', updateTask);
document.getElementById('copy-task-form').addEventListener('submit', copyTask);
document.getElementById('edit-assignment-form').addEventListener('submit', updateAssignment);
document.getElementById('rework-task-form').addEventListener('submit', sendForRework);
// Файлы
document.getElementById('files').addEventListener('change', updateFileList);
document.getElementById('edit-files').addEventListener('change', updateEditFileList);
// Настройки уведомлений
const notificationForm = document.getElementById('notification-settings-form');
if (notificationForm) {
notificationForm.addEventListener('submit', saveNotificationSettings);
}
// Инициализация загрузки файлов
initializeFileUploads();
}
// Функция для изменения вида задач
function changeTaskView() {
const select = document.getElementById('task-view-filter');
currentTaskView = select.value;
loadTasks();
}
// Переопределяем функцию loadTasks для фильтрации
(function() {
// Сохраняем оригинальную функцию loadTasks
const originalLoadTasks = window.loadTasks;
// Создаем новую функцию
window.loadTasks = async function() {
// Вызываем оригинальную функцию
if (typeof originalLoadTasks === 'function') {
await originalLoadTasks();
}
// Кэшируем все задачи
if (window.tasks && Array.isArray(window.tasks)) {
allTasksCache = [...window.tasks];
// Фильтруем задачи в зависимости от выбранного вида
if (currentTaskView !== 'all' && currentUser) {
let filteredTasks = [];
if (currentTaskView === 'my_assigned') {
// Показываем задачи, которые я назначил (я - создатель)
filteredTasks = window.tasks.filter(task => {
return parseInt(task.created_by) === currentUser.id;
});
} else if (currentTaskView === 'assigned_to_me') {
// Показываем задачи, назначенные мне (я - исполнитель)
filteredTasks = window.tasks.filter(task => {
// Проверяем, назначена ли задача текущему пользователю
if (task.assignments && Array.isArray(task.assignments)) {
return task.assignments.some(assignment =>
parseInt(assignment.user_id) === currentUser.id
);
}
return false;
});
}
// Обновляем глобальный массив задач
window.tasks = filteredTasks;
// Перерисовываем задачи
if (window.renderTasks && typeof window.renderTasks === 'function') {
window.renderTasks();
}
}
}
};
})();
// Обновленная функция для создания задачи
async function createTask(event) {
event.preventDefault();
if (!currentUser) {
alert('Требуется аутентификация');
return;
}
const title = document.getElementById('title').value;
const description = document.getElementById('description').value;
const taskType = document.getElementById('task-type').value;
// Получаем полную дату и время из отдельных полей
const fullDateTime = getFullDateTime('due-date', 'due-time');
if (!title || !fullDateTime) {
alert('Название задачи и дата выполнения обязательны');
return;
}
if (selectedUsers.length === 0) {
alert('Выберите хотя бы одного исполнителя');
return;
}
// Дополнительная проверка для задач типа "document"
if (taskType === 'document' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - секретари
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'Секретарь' ||
(typeof group === 'string' && group.includes('Секретарь'))
);
if (!hasSecretaryGroup) {
alert('Для задач типа "Согласование документа" можно выбирать только пользователей с правом "согласовать документы"');
return;
}
}
}
// Дополнительная проверка для задач типа "it"
if (taskType === 'it' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - it
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'ИТ специалист' ||
(typeof group === 'string' && group.includes('ИТ специалист'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "ИТ специалист"');
return;
}
}
}
// Дополнительная проверка для задач типа "ahch"
if (taskType === 'ahch' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - it
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'АХЧ' ||
(typeof group === 'string' && group.includes('АХЧ'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "сотрудники АХЧ"');
return;
}
}
}
// Дополнительная проверка для задач типа "psychologist"
if (taskType === 'psychologist' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - it
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'психолог' ||
(typeof group === 'string' && group.includes('психолог'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "сотрудники психологи"');
return;
}
}
}
// Дополнительная проверка для задач типа "speech_therapist"
if (taskType === 'speech_therapist' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - speech_therapist
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'логопед' ||
(typeof group === 'string' && group.includes('логопед'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "сотрудники логопеды"');
return;
}
}
}
// Дополнительная проверка для задач типа "hr"
if (taskType === 'hr' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - hr
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'Диспетчер' ||
(typeof group === 'string' && group.includes('Диспетчер'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "Диспетчер расписания"');
return;
}
}
}
// Дополнительная проверка для задач типа "certificate"
if (taskType === 'certificate' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - certificate
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'Администрация' ||
(typeof group === 'string' && group.includes('Администрация'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "секретари и завучи"');
return;
}
}
}
// Дополнительная проверка для задач типа "e_journal"
if (taskType === 'e_journal' && selectedUsers.length > 0) {
// Проверяем, что все выбранные пользователи - e_journal
for (const userId of selectedUsers) {
const groups = await getUserGroups(userId);
const hasSecretaryGroup = groups.some(group =>
group.name === 'Админ ЭЖ' ||
(typeof group === 'string' && group.includes('Админ ЭЖ'))
);
if (!hasSecretaryGroup) {
alert('Для задачи можно выбирать только пользователей из группы "администраторы электронного журнала"');
return;
}
}
}
const formData = new FormData();
formData.append('title', title);
formData.append('description', description);
formData.append('taskType', taskType);
formData.append('dueDate', fullDateTime);
selectedUsers.forEach(userId => {
formData.append('assignedUsers', userId);
});
const files = document.getElementById('files').files;
for (let i = 0; i < files.length; i++) {
formData.append('files', files[i]);
}
// Проверка прав для типа "regular"
const userGroups = currentUser?.groups || [];
const isAdmin = currentUser?.role === 'admin';
const hasTasksGroup = currentUser?.role === 'tasks';
const hasSecretaryGroup = currentUser?.role === 'secretary';
if (taskType === 'regular' && !(isAdmin || hasTasksGroup || hasSecretaryGroup)) {
alert('У вас нет прав для создания обычных задач. Выберите другой тип задачи.');
return;
}
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 = '';
document.getElementById('user-search').value = '';
selectedUsers = [];
// Сбрасываем дату и время
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
document.getElementById('due-date').value = tomorrow.toISOString().split('T')[0];
document.getElementById('due-time').value = '12:00';
// Сбрасываем активные кнопки
const timeButtons = document.querySelectorAll('.time-btn');
timeButtons.forEach(btn => btn.classList.remove('active'));
if (timeButtons.length > 0) {
timeButtons[0].classList.add('active');
}
// Обновляем отображение кнопок
updateDateTimeDisplay();
// Обновляем список пользователей
renderUsersChecklist();
// Загружаем задачи и логи
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 || '';
// Устанавливаем дату и время с помощью новой функции
setDateTimeForEdit(task.due_date);
// Устанавливаем выбранных пользователей
editSelectedUsers = task.assignments ? task.assignments.map(a => a.user_id) : [];
renderEditUsersChecklist(users);
// Показываем существующие файлы
currentEditTaskFiles = task.files || [];
updateEditFileList();
document.getElementById('edit-task-modal').style.display = 'block';
} catch (error) {
console.error('Ошибка:', error);
alert('Ошибка загрузки задачи');
}
}
// Обновленная функция обновления задачи
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 fullDateTime = getFullDateTime('edit-due-date', 'edit-due-time');
if (!fullDateTime) {
alert('Дата и время выполнения обязательны');
return;
}
// Используем editSelectedUsers
const assignedUserIds = editSelectedUsers;
const formData = new FormData();
formData.append('title', title);
formData.append('description', description);
formData.append('assignedUsers', JSON.stringify(assignedUserIds));
formData.append('dueDate', fullDateTime);
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('Задача успешно обновлена!');
closeEditModal();
loadTasks();
loadActivityLogs();
} else {
const error = await response.json();
alert(error.error || 'Ошибка обновления задачи');
}
} catch (error) {
console.error('Ошибка:', error);
alert('Ошибка обновления задачи');
}
}
// Обновленная функция создания копии задачи
async function copyTask(event) {
event.preventDefault();
const taskId = document.getElementById('copy-task-id').value;
// Получаем полную дату и время из отдельных полей
const fullDateTime = getFullDateTime('copy-due-date', 'copy-due-time');
if (!fullDateTime) {
alert('Дата и время выполнения обязательны для копии задачи');
return;
}
// Используем copySelectedUsers
const assignedUserIds = copySelectedUsers;
if (assignedUserIds.length === 0) {
alert('Выберите хотя бы одного исполнителя для копии задачи');
return;
}
try {
const response = await fetch(`/api/tasks/${taskId}/copy`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
assignedUsers: assignedUserIds,
dueDate: fullDateTime
})
});
if (response.ok) {
alert('Копия задачи успешно создана!');
closeCopyModal();
loadTasks();
loadActivityLogs();
} else {
const error = await response.json();
alert(error.error || 'Ошибка создания копии задачи');
}
} catch (error) {
console.error('Ошибка:', error);
alert('Ошибка создания копии задачи');
}
}
// Функция для отображения секции
function showSection(sectionName) {
document.querySelectorAll('.section').forEach(section => {
section.classList.remove('active');
});
document.getElementById(sectionName + '-section').classList.add('active');
if (sectionName === 'tasks') {
loadTasks();
} else if (sectionName === 'logs') {
loadActivityLogs();
} else if (sectionName === 'kanban') {
loadKanbanTasks();
}
// Загрузка профиля при переходе в личный кабинет
if (sectionName === 'profile') {
loadUserProfile();
loadNotificationSettings();
}
}
// Функция для отображения Канбан доски
function showKanbanSection() {
showSection('kanban');
}