diff --git a/public/nav-task-actions.js b/public/nav-task-actions.js index 2979ed1..921e0bb 100644 --- a/public/nav-task-actions.js +++ b/public/nav-task-actions.js @@ -1,18 +1,188 @@ // 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 escapeHtml(str) { + if (!str) return ''; + return String(str).replace(/[&<>]/g, function(m) { + if (m === '&') return '&'; + if (m === '<') return '<'; + if (m === '>') return '>'; + return m; + }); + } + function updateTaskCardDisplay(taskId, data) { + const taskCards = document.querySelectorAll(`[data-task-id="${taskId}"]`); + taskCards.forEach(card => { + let docContainer = card.querySelector('.document-fields-display'); + if (!docContainer) { + docContainer = document.createElement('div'); + docContainer.className = 'document-fields-display'; + const header = card.querySelector('.task-header'); + if (header) header.after(docContainer); + else card.prepend(docContainer); + } + let html = '
'; + if (data.document_n) html += `№: ${escapeHtml(data.document_n)}`; + if (data.document_d) html += `Дата: ${escapeHtml(data.document_d)}`; + if (data.document_a) html += `Автор: ${escapeHtml(data.document_a)}`; + if (!data.document_n && !data.document_d) html += 'Нет данных документа'; + html += '
'; + docContainer.innerHTML = html; + }); + } + +async function openDocumentFieldsModal(taskId) { + const existing = document.getElementById('doc-fields-modal'); + if (existing) existing.remove(); + + // Загружаем текущие поля + let fields = { document_n: '', document_d: '', document_a: '' }; + try { + const response = await fetch(`/api/tasks/${taskId}/document-fields`); + if (response.ok) { + const result = await response.json(); + fields = result.data || {}; + } + } catch (error) { + console.error('Ошибка загрузки реквизитов:', error); + } + + // Преобразуем дату из ДД.ММ.ГГГГ в YYYY-MM-DD для input type="date" + let dateValue = ''; + if (fields.document_d) { + const parts = fields.document_d.split('.'); + if (parts.length === 3) { + dateValue = `${parts[2]}-${parts[1]}-${parts[0]}`; + } + } + + // Проверяем права на редактирование + let canEdit = false; + const hasFields = !!(fields.document_n || fields.document_d); + if (hasFields) { + canEdit = fields.document_a === currentUser?.login; + } else { + try { + const groupsRes = await fetch(`/api2/idusers/user/${currentUser.id}/groups`); + if (groupsRes.ok) { + const groups = await groupsRes.json(); + canEdit = groups.some(g => g === 'Подписант' || g === 'Секретарь' || g.includes('Подписант') || g.includes('Секретарь')); + } + } catch (error) { + console.error('Ошибка проверки групп:', error); + } + } + + // Создаём модальное окно + const modal = document.createElement('div'); + modal.id = 'doc-fields-modal'; + modal.className = 'modal'; + modal.style.display = 'flex'; + modal.style.alignItems = 'center'; + modal.style.justifyContent = 'center'; + modal.style.zIndex = '10001'; + + modal.innerHTML = ` + + `; + + document.body.appendChild(modal); + + window.closeDocFieldsModal = function() { + const m = document.getElementById('doc-fields-modal'); + if (m) m.remove(); + delete window.closeDocFieldsModal; + }; + modal.addEventListener('click', (e) => { + if (e.target === modal) window.closeDocFieldsModal(); + }); + + if (canEdit) { + const saveBtn = document.getElementById('save-doc-fields'); + saveBtn.addEventListener('click', async () => { + const number = document.getElementById('doc-number').value.trim(); + const dateInput = document.getElementById('doc-date'); + let formattedDate = ''; + if (dateInput.value) { + // Преобразуем YYYY-MM-DD в ДД.ММ.ГГГГ + const parts = dateInput.value.split('-'); + if (parts.length === 3) { + formattedDate = `${parts[2]}.${parts[1]}.${parts[0]}`; + } + } + const author = document.getElementById('doc-author').value.trim() || currentUser?.login; + + saveBtn.disabled = true; + saveBtn.textContent = 'Сохранение...'; + + try { + const response = await fetch(`/api/tasks/${taskId}/document-fields`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + document_n: number || null, + document_d: formattedDate || null, + document_a: author + }) + }); + const result = await response.json(); + if (response.ok && result.success) { + alert('✅ Реквизиты сохранены'); + window.closeDocFieldsModal(); + const task = window.tasks?.find(t => t.id == taskId); + if (task) task.document_fields = result.data; + updateTaskCardDisplay(taskId, result.data); + if (typeof loadTasks === 'function') loadTasks(); + } else { + alert('❌ Ошибка: ' + (result.error || 'Неизвестная ошибка')); + } + } catch (error) { + console.error('Ошибка сохранения:', error); + alert('Сетевая ошибка'); + } finally { + saveBtn.disabled = false; + saveBtn.textContent = 'Сохранить'; + } + }); + } +} + + // ========== ОСНОВНАЯ ЛОГИКА МЕНЮ ДЕЙСТВИЙ ========== // Сбор доступных действий для конкретной задачи function buildActionsForTask(task) { - //log('buildActionsForTask called with task', task); const taskId = task.id; const isDeleted = task.status === 'deleted'; const isClosed = task.closed_at !== null; @@ -20,168 +190,146 @@ 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 - }); + + // ==== ДОБАВЛЕННЫЙ БЛОК: кнопки для текущего исполнителя + if (currentUser && !isDeleted && !isClosed) { + const myAssignment = task.assignments?.find(a => parseInt(a.user_id) === currentUser.id); + if (myAssignment) { + if (myAssignment.status === 'assigned') { + actions.push({ + label: '▶️ Приступить', + handler: () => window.updateStatus(taskId, currentUser.id, 'in_progress'), + primary: true + }); + } + 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 + }); + } + } } - // Кнопка "Выполнено" (если статус '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 (typeof openCopyModal === 'function') { - actions.push({ label: '📋 Создать копию', + actions.push({ + label: '📋 Создать копию', handler: () => openCopyModal(taskId), - primary: true + primary: true }); - log('nav-task-actions assignRemove_openModal yes'); - } else { - log('nav-task-actions assignRemove_openModal not'); - } + } + // Действия для активных (не удалённых, не закрытых) задач 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'); } } -// Подписание (только для документов, если текущий пользователь - исполнитель) -if (!isDeleted && !isClosed && task.task_type === 'document' && currentUser && task.assignments?.some(a => parseInt(a.user_id) === currentUser.id)) { - if (typeof window.signTask === 'function') { - actions.push({ - label: '✍️ Подписать', - handler: () => window.signTask(taskId, currentUser.id), - admin: true // primary_task - }); - } -} - // ${currentUser && currentUser.role === 'tasks' && canEdit || currentUser.role === 'admin' - // Администраторы и роль tasks -if (currentUser && (currentUser.role === 'admin' || (currentUser.role === 'tasks' && canEdit))) { + // Подписание (только для документов, если текущий пользователь - исполнитель) + if (!isDeleted && !isClosed && task.task_type === 'document' && currentUser && task.assignments?.some(a => parseInt(a.user_id) === currentUser.id)) { + if (typeof window.signTask === 'function') { + actions.push({ + label: '✍️ Подписать', + handler: () => window.signTask(taskId, currentUser.id), + admin: true + }); + } + } + + // Реквизиты документа (для задач типа document) + if (!isDeleted && !isClosed && task.task_type === 'document' && currentUser && task.assignments?.some(a => parseInt(a.user_id) === currentUser.id)) { + actions.push({ + label: '📄 Реквизиты', + handler: () => openDocumentFieldsModal(taskId), + admin: false + }); + } + + // Администраторы и роль tasks + if (currentUser && (currentUser.role === 'admin' || (currentUser.role === 'tasks' && canEdit))) { if (typeof assignAdd_openModal === 'function') { - actions.push({ label: '🧑‍💼➕ Добавить исполнителя', + 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: '🧑‍💼❌ Удалить исполнителя', + 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 (currentUser && (currentUser.role === 'admin' && currentUser.login === 'minicrm')) { - 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 (currentUser && (currentUser.role === 'admin' && currentUser.login === 'minicrm')) { + if (typeof openReworkModal === 'function') { + actions.push({ label: '🔄 Переделать документ', handler: () => openReworkModal(taskId) }); + } } } -} - // Кнопка "Создать ознакомление" для админов и tasks - if (currentUser && (currentUser.role === 'admin' || currentUser.role === 'tasks')) { - actions.push({ - label: '📖 Создать ознакомление', - handler: () => openAcquaintanceModal(task.id), - primary: true // можно отнести к админским или отдельной категории - }); - } + // Кнопка "Создать ознакомление" для админов и tasks + if (currentUser && (currentUser.role === 'admin' || currentUser.role === 'tasks')) { + actions.push({ + label: '📖 Создать ознакомление', + handler: () => openAcquaintanceModal(task.id), + primary: true + }); + } - // Доработка и изменение срока для необычных задач (исполнитель) -if (!isDeleted && !isClosed && task.task_type !== 'regular' && task.assignments && task.assignments.some(a => parseInt(a.user_id) === currentUser?.id)) { -if (typeof openReworkModal === 'function') { actions.push({ label: '🔄 Доработка', handler: () => openReworkModal(taskId),primary_task: true}); -log('nav-task-actions openReworkModal yes'); -} else {log('nav-task-actions openReworkModal not');} -if (typeof openChangeDeadlineModal === 'function') { actions.push({ label: '📅 Изменить срок', handler: () => openChangeDeadlineModal(taskId),primary_task: true }); -log('nav-task-actions openChangeDeadlineModal yes'); -} else {log('nav-task-actions openChangeDeadlineModal not');} -} + // Доработка и изменение срока для необычных задач (исполнитель) + if (!isDeleted && !isClosed && task.task_type !== 'regular' && task.assignments && task.assignments.some(a => parseInt(a.user_id) === currentUser?.id)) { + if (typeof openReworkModal === 'function') { + actions.push({ label: '🔄 Доработка', handler: () => openReworkModal(taskId), primary_task: true }); + } + if (typeof openChangeDeadlineModal === 'function') { + actions.push({ label: '📅 Изменить срок', handler: () => openChangeDeadlineModal(taskId), primary_task: true }); + } + } -if (!isDeleted && !isClosed && task.task_type == 'regular') { -if (typeof closeTask === 'function') { actions.push({ label: '🔒 Закрыть задачу', handler: () => closeTask(taskId),admin: true }); -log('nav-task-actions closeTask yes'); -} else {log('nav-task-actions closeTask not');} -} + if (!isDeleted && !isClosed && task.task_type == 'regular') { + if (typeof closeTask === 'function') { + actions.push({ label: '🔒 Закрыть задачу', handler: () => closeTask(taskId), admin: true }); + } + } -if (canEdit && !isDeleted && !isClosed && currentUser.role === 'admin') { - if (typeof deleteTask === 'function') actions.push({ label: '🗑️ Удалить', handler: () => deleteTask(taskId) }); -} -if (currentUser && currentUser.login === 'minicrm') { - // Закрытие (только 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 (currentUser && 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) }); + } } - // Восстановление удалённой (только админ) - if (isDeleted && window.currentUser?.role === 'admin') { - if (typeof restoreTask === 'function') actions.push({ label: '↶ Восстановить', handler: () => restoreTask(taskId) }); - } -} - //log('Actions built:', actions); return actions; } @@ -206,7 +354,6 @@ if (currentUser && currentUser.login === 'minicrm') { const menuBtn = e.target.closest('.task-actions-menu-btn'); if (!menuBtn) return; - //log('Menu button clicked', menuBtn); e.preventDefault(); e.stopPropagation(); @@ -227,12 +374,11 @@ if (currentUser && currentUser.login === 'minicrm') { 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 adminActions = actions.filter(a => a.admin && !a.primary); const taskActions = actions.filter(a => a.primary_task && !a.primary && !a.primary); const userActions = actions.filter(a => !a.primary && !a.admin && !a.primary_task); - // Создаём затемнение + const overlay = document.createElement('div'); overlay.id = 'task-action-modal'; overlay.style.position = 'fixed'; @@ -246,7 +392,6 @@ if (currentUser && currentUser.login === 'minicrm') { overlay.style.alignItems = 'center'; overlay.style.justifyContent = 'center'; - // Создаём контейнер модального окна const modal = document.createElement('div'); modal.style.backgroundColor = 'white'; modal.style.borderRadius = '12px'; @@ -258,7 +403,6 @@ if (currentUser && currentUser.login === 'minicrm') { modal.style.maxHeight = '85vh'; modal.style.overflowY = 'auto'; - // Заголовок const header = document.createElement('div'); header.style.display = 'flex'; header.style.justifyContent = 'space-between'; @@ -290,140 +434,142 @@ if (currentUser && currentUser.login === 'minicrm') { 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); -} -// === Блок taskActions === -if (taskActions.length > 0) { - const taskContainer = document.createElement('div'); - taskContainer.style.marginBottom = '20px'; - taskActions.forEach(a => { - const btn = document.createElement('button'); - btn.textContent = a.label; - btn.style.cssText = ` - width: 100%; - padding: 14px; - background-color: #dfc63cff; // цвет - 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 = '#dfc63cff'; - btn.onmouseout = () => btn.style.backgroundColor = '#dfc63cff'; - btn.onclick = (event) => { - event.stopPropagation(); - a.handler(); - removeModal(); - }; - taskContainer.appendChild(btn); - }); - modal.appendChild(taskContainer); -} -// === Блок 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); -} + // БЛОК: 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); + } + + // БЛОК: taskActions + if (taskActions.length > 0) { + const taskContainer = document.createElement('div'); + taskContainer.style.marginBottom = '20px'; + taskActions.forEach(a => { + const btn = document.createElement('button'); + btn.textContent = a.label; + btn.style.cssText = ` + width: 100%; + padding: 14px; + background-color: #dfc63cff; + 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 = '#dfc63cff'; + btn.onmouseout = () => btn.style.backgroundColor = '#dfc63cff'; + btn.onclick = (event) => { + event.stopPropagation(); + a.handler(); + removeModal(); + }; + taskContainer.appendChild(btn); + }); + modal.appendChild(taskContainer); + } + + // БЛОК: 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); + } -// === Блок остальных (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(); @@ -431,5 +577,11 @@ if (userActions.length > 0) { }); }); + // Экспортируем функции для использования в HTML (например, closeDocFieldsModal) + window.closeDocFieldsModal = function() { + const m = document.getElementById('doc-fields-modal'); + if (m) m.remove(); + }; + //console.log('nav-task-actions.js loaded (centered modal)'); })(); \ No newline at end of file