372 lines
16 KiB
JavaScript
372 lines
16 KiB
JavaScript
// nav-task-actions.js – модальное окно с действиями задачи (сетка 3 колонки, центрированное)
|
||
(function() {
|
||
'use strict';
|
||
// Управление логированием: установите window.navTaskActionsLog = 1 для включения логов
|
||
const LOG_ENABLED = 0;
|
||
function log(...args) {
|
||
if (LOG_ENABLED) console.log(...args);
|
||
}
|
||
|
||
log('currentUser:', currentUser);
|
||
//log('currentUser.role:', currentUser.role);
|
||
|
||
// Сбор доступных действий для конкретной задачи
|
||
function buildActionsForTask(task) {
|
||
//log('buildActionsForTask called with task', task);
|
||
const taskId = task.id;
|
||
const isDeleted = task.status === 'deleted';
|
||
const isClosed = task.closed_at !== null;
|
||
const userRole = window.getUserRoleInTask ? window.getUserRoleInTask(task) : 'Наблюдатель';
|
||
const canEdit = window.canUserEditTask ? window.canUserEditTask(task) : false;
|
||
|
||
const actions = [];
|
||
// ==== ДОБАВЛЕННЫЙ БЛОК: кнопки для текущего исполнителя
|
||
if (currentUser && !isDeleted && !isClosed) {
|
||
const myAssignment = task.assignments?.find(a => parseInt(a.user_id) === currentUser.id);
|
||
if (myAssignment) {
|
||
// Кнопка "Приступить" (если статус 'assigned')
|
||
if (myAssignment.status === 'assigned') {
|
||
actions.push({
|
||
label: '▶️ Приступить',
|
||
handler: () => window.updateStatus(taskId, currentUser.id, 'in_progress'),
|
||
primary: true
|
||
});
|
||
}
|
||
// Кнопка "Выполнено" (если статус 'in_progress', 'overdue' или 'rework')
|
||
if (['in_progress', 'overdue', 'rework'].includes(myAssignment.status)) {
|
||
const isDocumentTask = task.task_type === 'document';
|
||
const handler = isDocumentTask
|
||
? () => window.openDocumentCompleteModal(taskId, currentUser.id)
|
||
: () => window.updateStatus(taskId, currentUser.id, 'completed');
|
||
actions.push({
|
||
label: '✅ Выполнено',
|
||
handler: handler,
|
||
primary: true
|
||
});
|
||
}
|
||
}
|
||
}
|
||
// Действия для активных (не удалённых, не закрытых) задач
|
||
if (!isDeleted && !isClosed && currentUser.login === 'minicrm') {
|
||
if (typeof openTaskChat === 'function') {
|
||
actions.push({ label: '💬 Чат', handler: () => openTaskChat(taskId) });
|
||
log('nav-task-actions openTaskChat yes');
|
||
} else {
|
||
log('nav-task-actions openTaskChat not');
|
||
}
|
||
if (typeof openAddFileModal === 'function') {
|
||
actions.push({ label: '📎 Добавить файл', handler: () => openAddFileModal(taskId) });
|
||
log('nav-task-actions openAddFileModal yes');
|
||
} else {
|
||
log('nav-task-actions openAddFileModal not');
|
||
}
|
||
}
|
||
// Специальные пользователи
|
||
if (currentUser && currentUser.login === 'minicrm') {
|
||
if (typeof openEditModal === 'function') {
|
||
actions.push({ label: '✏️ Редактировать', handler: () => openEditModal(taskId) });
|
||
log('nav-task-actions openEditModal yes');
|
||
} else {
|
||
log('nav-task-actions openEditModal not');
|
||
}
|
||
////}
|
||
//if (currentUser && currentUser.login === 'kalugin.o') {
|
||
if (typeof openManageAssigneesModal === 'function') {
|
||
actions.push({ label: '👥 Управление исполнителями', handler: () => openManageAssigneesModal(taskId) });
|
||
log('nav-task-actions openManageAssigneesModal yes');
|
||
} else {
|
||
log('nav-task-actions openManageAssigneesModal not');
|
||
}
|
||
}
|
||
|
||
// ${currentUser && currentUser.role === 'tasks' && canEdit || currentUser.role === 'admin'
|
||
// Администраторы и роль tasks
|
||
if (currentUser && (currentUser.role === 'admin' || (currentUser.role === 'tasks' && canEdit))) {
|
||
|
||
if (typeof assignAdd_openModal === 'function') {
|
||
actions.push({ label: '🧑💼➕ Добавить исполнителя',
|
||
handler: () => assignAdd_openModal(taskId),
|
||
admin: true
|
||
});
|
||
log('nav-task-actions assignAdd_openModal yes');
|
||
} else {
|
||
log('nav-task-actions assignAdd_openModal not');
|
||
}
|
||
if (typeof assignRemove_openModal === 'function') {
|
||
actions.push({ label: '🧑💼❌ Удалить исполнителя',
|
||
handler: () => assignRemove_openModal(taskId),
|
||
admin: true
|
||
});
|
||
log('nav-task-actions assignRemove_openModal yes');
|
||
} else {
|
||
log('nav-task-actions assignRemove_openModal not');
|
||
}
|
||
//}
|
||
|
||
// Копия – доступна всем, у кого есть кнопка
|
||
if (typeof openCopyModal === 'function') {
|
||
actions.push({ label: '📋 Создать копию', handler: () => openCopyModal(taskId) });
|
||
log('nav-task-actions assignRemove_openModal yes');
|
||
} else {
|
||
log('nav-task-actions assignRemove_openModal not');
|
||
}
|
||
|
||
// Доработка для документа (исполнитель)
|
||
//if (task.task_type === 'document' && userRole === 'Исполнитель') {
|
||
if (typeof openReworkModal === 'function') {
|
||
actions.push({ label: '🔄 Переделать документ', handler: () => openReworkModal(taskId) });
|
||
log('nav-task-actions assignRemove_openModal yes');
|
||
} else {
|
||
log('nav-task-actions assignRemove_openModal not');
|
||
}
|
||
//}
|
||
|
||
// Доработка и изменение срока для необычных задач (исполнитель)
|
||
//if (!isDeleted && !isClosed && task.task_type !== 'regular' &&task.assignments && task.assignments.some(a => parseInt(a.user_id) === window.currentUser?.id)) {
|
||
if (typeof openReworkModal === 'function') { actions.push({ label: '🔄 Доработка', handler: () => openReworkModal(taskId) });
|
||
log('nav-task-actions openReworkModal yes');
|
||
} else {log('nav-task-actions openReworkModal not');}
|
||
if (typeof openChangeDeadlineModal === 'function') { actions.push({ label: '📅 Изменить срок', handler: () => openChangeDeadlineModal(taskId) });
|
||
log('nav-task-actions openChangeDeadlineModal yes');
|
||
} else {log('nav-task-actions openChangeDeadlineModal not');}
|
||
//}
|
||
|
||
// Закрытие (только minicrm)
|
||
//if (window.currentUser && window.currentUser.login === 'minicrm') {
|
||
if (typeof closeTask === 'function') actions.push({ label: '🔒 Закрыть задачу', handler: () => closeTask(taskId) });
|
||
//}
|
||
|
||
// Удаление (если есть права)
|
||
if (canEdit && !isDeleted && !isClosed && currentUser.role === 'admin') {
|
||
if (typeof deleteTask === 'function') actions.push({ label: '🗑️ Удалить', handler: () => deleteTask(taskId) });
|
||
}
|
||
|
||
// Открытие закрытой задачи
|
||
if (isClosed && canEdit) {
|
||
if (typeof reopenTask === 'function') actions.push({ label: '🔓 Открыть задачу', handler: () => reopenTask(taskId) });
|
||
}
|
||
|
||
// Восстановление удалённой (только админ)
|
||
if (isDeleted && window.currentUser?.role === 'admin') {
|
||
if (typeof restoreTask === 'function') actions.push({ label: '↶ Восстановить', handler: () => restoreTask(taskId) });
|
||
}
|
||
}
|
||
//log('Actions built:', actions);
|
||
return actions;
|
||
}
|
||
|
||
// Рендеринг кнопки меню
|
||
window.renderTaskActions = function(task) {
|
||
if (!task) return '';
|
||
return `
|
||
<div class="task-actions-menu-container">
|
||
<button class="task-actions-menu-btn" data-task-id="${task.id}">⋮ Действия</button>
|
||
</div>
|
||
`;
|
||
};
|
||
|
||
// Удалить модальное окно, если оно есть
|
||
function removeModal() {
|
||
const existing = document.getElementById('task-action-modal');
|
||
if (existing) existing.remove();
|
||
}
|
||
|
||
// Обработчик клика на кнопку меню
|
||
document.addEventListener('click', function(e) {
|
||
const menuBtn = e.target.closest('.task-actions-menu-btn');
|
||
if (!menuBtn) return;
|
||
|
||
//log('Menu button clicked', menuBtn);
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
|
||
removeModal();
|
||
|
||
const taskId = menuBtn.dataset.taskId;
|
||
if (!taskId) {
|
||
console.error('No task id found on button');
|
||
return;
|
||
}
|
||
|
||
const task = window.tasks?.find(t => t.id == taskId);
|
||
if (!task) {
|
||
console.error('Task not found for id', taskId);
|
||
return;
|
||
}
|
||
|
||
const actions = buildActionsForTask(task);
|
||
if (actions.length === 0) return;
|
||
|
||
// primary
|
||
const primaryActions = actions.filter(a => a.primary);
|
||
const adminActions = actions.filter(a => a.admin && !a.primary);
|
||
const userActions = actions.filter(a => !a.primary && !a.admin);
|
||
// Создаём затемнение
|
||
const overlay = document.createElement('div');
|
||
overlay.id = 'task-action-modal';
|
||
overlay.style.position = 'fixed';
|
||
overlay.style.top = '0';
|
||
overlay.style.left = '0';
|
||
overlay.style.width = '100%';
|
||
overlay.style.height = '100%';
|
||
overlay.style.backgroundColor = 'rgba(0,0,0,0.5)';
|
||
overlay.style.zIndex = '10000';
|
||
overlay.style.display = 'flex';
|
||
overlay.style.alignItems = 'center';
|
||
overlay.style.justifyContent = 'center';
|
||
|
||
// Создаём контейнер модального окна
|
||
const modal = document.createElement('div');
|
||
modal.style.backgroundColor = 'white';
|
||
modal.style.borderRadius = '12px';
|
||
modal.style.padding = '25px';
|
||
modal.style.maxWidth = '500px';
|
||
modal.style.width = '90%';
|
||
modal.style.boxShadow = '0 10px 40px rgba(0,0,0,0.2)';
|
||
modal.style.position = 'relative';
|
||
modal.style.maxHeight = '85vh';
|
||
modal.style.overflowY = 'auto';
|
||
|
||
// Заголовок
|
||
const header = document.createElement('div');
|
||
header.style.display = 'flex';
|
||
header.style.justifyContent = 'space-between';
|
||
header.style.alignItems = 'center';
|
||
header.style.marginBottom = '20px';
|
||
header.style.paddingBottom = '10px';
|
||
header.style.borderBottom = '1px solid #eee';
|
||
|
||
const title = document.createElement('h3');
|
||
title.style.margin = '0';
|
||
title.style.fontSize = '18px';
|
||
title.style.color = '#333';
|
||
title.style.flex = '1';
|
||
title.style.textAlign = 'center';
|
||
title.textContent = `Действия для задачи #${taskId}`;
|
||
|
||
const closeBtn = document.createElement('span');
|
||
closeBtn.innerHTML = '×';
|
||
closeBtn.style.fontSize = '28px';
|
||
closeBtn.style.fontWeight = 'bold';
|
||
closeBtn.style.cursor = 'pointer';
|
||
closeBtn.style.color = '#999';
|
||
closeBtn.style.transition = 'color 0.2s';
|
||
closeBtn.onmouseover = () => closeBtn.style.color = '#e74c3c';
|
||
closeBtn.onmouseout = () => closeBtn.style.color = '#999';
|
||
closeBtn.onclick = () => removeModal();
|
||
|
||
header.appendChild(title);
|
||
header.appendChild(closeBtn);
|
||
modal.appendChild(header);
|
||
|
||
// === БЛОК: primary actions ===
|
||
if (primaryActions.length > 0) {
|
||
const primaryContainer = document.createElement('div');
|
||
primaryContainer.style.marginBottom = '20px';
|
||
primaryActions.forEach(a => {
|
||
const btn = document.createElement('button');
|
||
btn.textContent = a.label;
|
||
btn.style.cssText = `
|
||
width: 100%;
|
||
padding: 14px;
|
||
background-color: #27ae60;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background-color 0.2s;
|
||
margin-bottom: 10px;
|
||
`;
|
||
btn.onmouseover = () => { btn.style.backgroundColor = '#229954'; };
|
||
btn.onmouseout = () => { btn.style.backgroundColor = '#27ae60'; };
|
||
btn.onclick = (event) => {
|
||
event.stopPropagation();
|
||
a.handler();
|
||
removeModal();
|
||
};
|
||
primaryContainer.appendChild(btn);
|
||
});
|
||
modal.appendChild(primaryContainer);
|
||
}
|
||
// === Блок admin ===
|
||
if (adminActions.length > 0) {
|
||
const adminContainer = document.createElement('div');
|
||
adminContainer.style.marginBottom = '20px';
|
||
adminActions.forEach(a => {
|
||
const btn = document.createElement('button');
|
||
btn.textContent = a.label;
|
||
btn.style.cssText = `
|
||
width: 100%;
|
||
padding: 14px;
|
||
background-color: #e74c3c; // красный цвет для админских
|
||
color: white;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background-color 0.2s;
|
||
margin-bottom: 10px;
|
||
`;
|
||
btn.onmouseover = () => btn.style.backgroundColor = '#c0392b';
|
||
btn.onmouseout = () => btn.style.backgroundColor = '#e74c3c';
|
||
btn.onclick = (event) => {
|
||
event.stopPropagation();
|
||
a.handler();
|
||
removeModal();
|
||
};
|
||
adminContainer.appendChild(btn);
|
||
});
|
||
modal.appendChild(adminContainer);
|
||
}
|
||
// === Блок остальных (user) ===
|
||
if (userActions.length > 0) {
|
||
const grid = document.createElement('div');
|
||
grid.style.cssText = `
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
justify-content: center;
|
||
`;
|
||
userActions.forEach(a => {
|
||
const btn = document.createElement('button');
|
||
btn.textContent = a.label;
|
||
btn.style.cssText = `
|
||
flex: 0 0 calc(33.333% - 10px);
|
||
min-width: 120px;
|
||
padding: 12px 8px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
background-color: #3498db;
|
||
color: white;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background-color 0.2s;
|
||
`;
|
||
btn.onmouseover = () => btn.style.backgroundColor = '#2980b9';
|
||
btn.onmouseout = () => btn.style.backgroundColor = '#3498db';
|
||
btn.onclick = (event) => {
|
||
event.stopPropagation();
|
||
a.handler();
|
||
removeModal();
|
||
};
|
||
grid.appendChild(btn);
|
||
});
|
||
modal.appendChild(grid);
|
||
}
|
||
overlay.appendChild(modal);
|
||
document.body.appendChild(overlay);
|
||
|
||
// Закрытие по клику на затемнение
|
||
overlay.addEventListener('click', function(event) {
|
||
if (event.target === overlay) {
|
||
removeModal();
|
||
}
|
||
});
|
||
});
|
||
|
||
//console.log('nav-task-actions.js loaded (centered modal)');
|
||
})(); |