From 613971b79e6bc3cc943a79f3d7db6c1a6605b21d Mon Sep 17 00:00:00 2001 From: kalugin66 Date: Wed, 4 Mar 2026 20:48:43 +0500 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/nav-task-actions.js | 265 +++++++++++++++++++++++++------------ 1 file changed, 182 insertions(+), 83 deletions(-) diff --git a/public/nav-task-actions.js b/public/nav-task-actions.js index 4591964..bb9d8d7 100644 --- a/public/nav-task-actions.js +++ b/public/nav-task-actions.js @@ -1,10 +1,14 @@ -// nav-task-actions.js – выпадающее меню действий задачи +// nav-task-actions.js – модальное окно с действиями задачи (сетка 3 колонки, центрированное) (function() { 'use strict'; - + // Управление логированием: установите window.navTaskActionsLog = 1 для включения логов + const LOG_ENABLED = 0; + function log(...args) { + if (LOG_ENABLED) console.log(...args); + } // Сбор доступных действий для конкретной задачи function buildActionsForTask(task) { - console.log('buildActionsForTask called with task', task); + //log('buildActionsForTask called with task', task); const taskId = task.id; const isDeleted = task.status === 'deleted'; const isClosed = task.closed_at !== null; @@ -15,43 +19,86 @@ // Действия для активных (не удалённых, не закрытых) задач if (!isDeleted && !isClosed) { - if (typeof openTaskChat === 'function') actions.push({ label: '💬 Чат', handler: () => openTaskChat(taskId) }); - if (typeof openAddFileModal === 'function') actions.push({ label: '📎 Добавить файл', handler: () => openAddFileModal(taskId) }); + 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 (window.currentUser && window.currentUser.login === 'minicrm') { - if (typeof openEditModal === 'function') actions.push({ label: '✏️ Редактировать', handler: () => openEditModal(taskId) }); - } - if (window.currentUser && window.currentUser.login === 'kalugin.o') { - if (typeof openManageAssigneesModal === 'function') actions.push({ label: '👥 Управление исполнителями', handler: () => openManageAssigneesModal(taskId) }); - } +if (window.currentUser && window.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 (window.currentUser && window.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'); + } + //} // Администраторы и роль tasks - if (window.currentUser && (window.currentUser.role === 'admin' || (window.currentUser.role === 'tasks' && canEdit))) { - if (typeof assignAdd_openModal === 'function') actions.push({ label: '🧑‍💼➕ Добавить исполнителя', handler: () => assignAdd_openModal(taskId) }); - if (typeof assignRemove_openModal === 'function') actions.push({ label: '🧑‍💼❌ Удалить исполнителя', handler: () => assignRemove_openModal(taskId) }); - } + //if (window.currentUser && (window.currentUser.role === 'admin' || (window.currentUser.role === 'tasks' && canEdit))) { + if (typeof assignAdd_openModal === 'function') { + actions.push({ label: '🧑‍💼➕ Добавить исполнителя', handler: () => assignAdd_openModal(taskId) }); + 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) }); + 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) }); + 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) }); - } + //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) }); - if (typeof openChangeDeadlineModal === 'function') actions.push({ label: '📅 Изменить срок', handler: () => openChangeDeadlineModal(taskId) }); - } +//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 (window.currentUser && window.currentUser.login === 'minicrm') { if (typeof closeTask === 'function') actions.push({ label: '🔒 Закрыть задачу', handler: () => closeTask(taskId) }); - } + //} // Удаление (если есть права) if (canEdit && !isDeleted && !isClosed) { @@ -67,12 +114,12 @@ if (isDeleted && window.currentUser?.role === 'admin') { if (typeof restoreTask === 'function') actions.push({ label: '↶ Восстановить', handler: () => restoreTask(taskId) }); } - - console.log('Actions built:', actions); +} + //log('Actions built:', actions); return actions; } - // Рендеринг кнопки меню (без встроенного dropdown) + // Рендеринг кнопки меню window.renderTaskActions = function(task) { if (!task) return ''; return ` @@ -82,9 +129,9 @@ `; }; - // Удалить текущее меню, если есть - function removeCurrentMenu() { - const existing = document.getElementById('task-action-menu'); + // Удалить модальное окно, если оно есть + function removeModal() { + const existing = document.getElementById('task-action-modal'); if (existing) existing.remove(); } @@ -93,12 +140,11 @@ const menuBtn = e.target.closest('.task-actions-menu-btn'); if (!menuBtn) return; - console.log('Menu button clicked', menuBtn); + //log('Menu button clicked', menuBtn); e.preventDefault(); e.stopPropagation(); - // Удаляем предыдущее меню - removeCurrentMenu(); + removeModal(); const taskId = menuBtn.dataset.taskId; if (!taskId) { @@ -112,63 +158,116 @@ return; } - // Построить список действий const actions = buildActionsForTask(task); - if (actions.length === 0) { - return; - } + if (actions.length === 0) return; - // Создаём элемент меню - const menu = document.createElement('div'); - menu.id = 'task-action-menu'; - menu.className = 'task-actions-dropdown'; - menu.style.position = 'absolute'; - menu.style.zIndex = '10000'; - menu.style.backgroundColor = 'white'; - menu.style.border = '1px solid #ccc'; - menu.style.borderRadius = '8px'; - menu.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; - menu.style.minWidth = '200px'; - menu.style.padding = '8px 0'; + // Создаём затемнение + 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.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); + + // Сетка кнопок (flex-wrap с 3 колонками) + const grid = document.createElement('div'); + grid.style.display = 'flex'; + grid.style.flexWrap = 'wrap'; + grid.style.gap = '10px'; + grid.style.justifyContent = 'center'; - // Заполняем пунктами actions.forEach(a => { - const item = document.createElement('div'); - item.className = 'menu-item'; - item.textContent = a.label; - item.style.padding = '10px 16px'; - item.style.cursor = 'pointer'; - item.style.fontSize = '14px'; - item.style.color = '#333'; - item.style.transition = 'background 0.2s'; - item.addEventListener('mouseenter', () => { item.style.backgroundColor = '#f8f9fa'; }); - item.addEventListener('mouseleave', () => { item.style.backgroundColor = 'transparent'; }); - item.addEventListener('click', (event) => { + const btn = document.createElement('button'); + btn.textContent = a.label; + btn.style.flex = '0 0 calc(33.333% - 10px)'; + btn.style.minWidth = '120px'; + btn.style.padding = '12px 8px'; + btn.style.border = 'none'; + btn.style.borderRadius = '8px'; + btn.style.backgroundColor = '#3498db'; + btn.style.color = 'white'; + btn.style.fontSize = '14px'; + btn.style.fontWeight = '500'; + btn.style.cursor = 'pointer'; + btn.style.transition = 'all 0.2s'; + btn.style.boxShadow = '0 2px 5px rgba(52,152,219,0.3)'; + + btn.onmouseover = () => { + btn.style.transform = 'translateY(-2px)'; + btn.style.boxShadow = '0 4px 10px rgba(52,152,219,0.4)'; + }; + btn.onmouseout = () => { + btn.style.transform = 'translateY(0)'; + btn.style.boxShadow = '0 2px 5px rgba(52,152,219,0.3)'; + }; + btn.onclick = (event) => { event.stopPropagation(); a.handler(); - removeCurrentMenu(); - }); - menu.appendChild(item); + removeModal(); + }; + + grid.appendChild(btn); }); - // Позиционируем - const rect = menuBtn.getBoundingClientRect(); - menu.style.top = (rect.bottom + window.scrollY) + 'px'; - menu.style.left = (rect.left + window.scrollX) + 'px'; + modal.appendChild(grid); + overlay.appendChild(modal); + document.body.appendChild(overlay); - // Добавляем в body - document.body.appendChild(menu); - - // Закрытие при клике вне меню - setTimeout(() => { - document.addEventListener('click', function closeMenu(e) { - if (!menu.contains(e.target) && !menuBtn.contains(e.target)) { - removeCurrentMenu(); - document.removeEventListener('click', closeMenu); - } - }); - }, 0); + // Закрытие по клику на затемнение + overlay.addEventListener('click', function(event) { + if (event.target === overlay) { + removeModal(); + } + }); }); - console.log('nav-task-actions.js loaded'); + //console.log('nav-task-actions.js loaded (centered modal)'); })(); \ No newline at end of file