Files
minicrm/public/signature.js

345 lines
15 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.
// signature.js - Универсальный скрипт для подписания задач
(function() {
'use strict';
// Конфигурация
const CONFIG = {
signerGroup: 'Подписант',
apiEndpoint: '/api2/idusers',
usersEndpoint: '/api/users',
replaceEndpoint: '/api/tasks/${taskId}/replace-assignee',
replaceAllEndpoint: '/api/tasks/${taskId}/replace-all-assignees',
taskTypeDocument: 'document' // Тип задачи "Документ"
};
// Текущий пользователь
let currentUser = null;
// Является ли текущий пользователь подписантом
let isCurrentUserSigner = false;
// Получение текущего пользователя
async function getCurrentUser() {
try {
const response = await fetch('/api/user');
const data = await response.json();
if (data.user) {
currentUser = data.user;
console.log('✅ Signature: текущий пользователь', currentUser);
// Проверяем, является ли пользователь подписантом
await checkIfUserIsSigner();
}
return currentUser;
} catch (error) {
console.error('❌ Signature: ошибка получения пользователя', error);
return null;
}
}
// Проверка, является ли текущий пользователь подписантом
async function checkIfUserIsSigner() {
if (!currentUser) return false;
try {
// Получаем всех подписантов
const signers = await getSigners();
// Проверяем, есть ли текущий пользователь в списке подписантов
isCurrentUserSigner = signers.some(signer =>
signer.id === currentUser.id ||
signer.login === currentUser.login ||
signer.name === currentUser.name
);
console.log('✅ Signature: пользователь является подписантом?', isCurrentUserSigner);
return isCurrentUserSigner;
} catch (error) {
console.error('❌ Signature: ошибка проверки подписанта', error);
return false;
}
}
// Получение подписантов
async function getSigners() {
try {
const response = await fetch(CONFIG.apiEndpoint);
if (!response.ok) return await getSignersFallback();
const data = await response.json();
const signers = data.filter(user =>
user.is_active && (
user.group_name?.toLowerCase().includes(CONFIG.signerGroup.toLowerCase()) ||
user.metadata?.groups?.some(g => g.toLowerCase().includes(CONFIG.signerGroup.toLowerCase())) ||
user.ldap_group?.toLowerCase().includes(CONFIG.signerGroup.toLowerCase())
)
);
return signers.map(s => ({
id: s.user_id,
name: s.user_name || s.login || 'Неизвестно',
login: s.user_login || s.login || ''
}));
} catch {
return await getSignersFallback();
}
}
// Запасной метод получения подписантов
async function getSignersFallback() {
try {
const res = await fetch(CONFIG.usersEndpoint);
if (!res.ok) return [];
const users = await res.json();
return users.filter(u => u.role === 'admin' || u.role === 'signer')
.map(u => ({ id: u.id, name: u.name || u.login, login: u.login }));
} catch {
return [];
}
}
// Основная функция подписания
window.signTask = async function(taskId, userId) {
// Если userId не передан, используем текущего пользователя
const targetUserId = userId || currentUser?.id;
if (!targetUserId) {
alert('❌ Не удалось определить текущего пользователя');
return false;
}
try {
const signers = await getSigners();
if (!signers.length) {
alert('❌ Секретари не найдены в системе');
return false;
}
const names = signers.map(s => `${s.name} (${s.login})`).join('\n');
const msg = signers.length === 1
? `✍️ Назначить подписанта?\n\n${names}`
: `✍️ Назначить подписантов?\n\n${names}`;
if (!confirm(msg)) return false;
let response;
if (signers.length > 1) {
const url = CONFIG.replaceAllEndpoint.replace('${taskId}', taskId);
response = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ newAssigneeIds: signers.map(s => s.id) })
});
} else {
const url = CONFIG.replaceEndpoint.replace('${taskId}', taskId);
response = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
oldAssigneeId: targetUserId,
newAssigneeId: signers[0].id
})
});
}
if (response.ok) {
alert(`✅ Задача ${signers.length > 1 ? 'назначена подписантам' : 'переназначена подписанту'}`);
// Пробуем перезагрузить задачи разными способами
if (window.TasksType && typeof window.TasksType.loadTasks === 'function') {
window.TasksType.loadTasks();
} else if (window.loadTasks && typeof window.loadTasks === 'function') {
window.loadTasks();
} else {
// Если нет функций загрузки, просто обновляем страницу
setTimeout(() => window.location.reload(), 1500);
}
return true;
} else {
const err = await response.json();
alert('❌ Ошибка: ' + (err.error || 'Неизвестная ошибка'));
return false;
}
} catch (error) {
console.error('❌ Signature error:', error);
alert('❌ Сетевая ошибка: ' + error.message);
return false;
}
};
// Обновление статуса задачи
window.updateTaskStatus = async function(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) {
if (window.TasksType && typeof window.TasksType.loadTasks === 'function') {
window.TasksType.loadTasks();
} else if (window.loadTasks && typeof window.loadTasks === 'function') {
window.loadTasks();
}
return true;
} else {
const err = await response.json();
alert('❌ Ошибка: ' + (err.error || 'Неизвестная ошибка'));
return false;
}
} catch (error) {
console.error('❌ Status update error:', error);
alert('❌ Сетевая ошибка');
return false;
}
};
// Получение типа задачи из элемента карточки
function getTaskTypeFromCard(card) {
// Ищем элемент с типом задачи
const typeElement = card.querySelector('.task-type-badge, .task-type');
if (typeElement) {
const classList = typeElement.className;
if (classList.includes('document') || classList.includes('Документ')) {
return 'document';
}
}
// Пробуем найти по тексту
const cardText = card.textContent || '';
if (cardText.includes('Документ') || cardText.includes('document')) {
return 'document';
}
return null;
}
// Функция для добавления кнопок в существующие карточки задач
window.addSignatureButtons = function() {
// Показываем кнопку только если пользователь является подписантом
if (!currentUser || isCurrentUserSigner) return;
document.querySelectorAll('[data-task-id]').forEach(card => {
// Проверяем, есть ли уже кнопка
if (card.querySelector('.signature-btn')) return;
// Проверяем тип задачи - только для документов
const taskType = getTaskTypeFromCard(card);
if (taskType !== CONFIG.taskTypeDocument) return;
const taskId = card.dataset.taskId;
// Ищем контейнер action-buttons
const actionsContainer = card.querySelector('.action-buttons');
if (actionsContainer) {
const btn = document.createElement('button');
btn.className = 'signature-btn action-btn sign-btn';
btn.innerHTML = '✍️ Подписать';
btn.onclick = (e) => {
e.stopPropagation();
window.signTask(taskId, currentUser.id);
};
btn.title = 'Передать подписанту';
actionsContainer.appendChild(btn);
}
});
};
// Наблюдатель за изменениями DOM для динамической добавления кнопок
function observeDOM() {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length) {
window.addSignatureButtons();
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// Функция для получения отображаемого имени типа задачи
function getTaskTypeDisplayName(type) {
const typeMap = {
'document': 'Документ',
'task': 'Задача',
'bug': 'Ошибка',
'request': 'Заявка'
};
return typeMap[type] || type;
}
// Инициализация при загрузке страницы
async function init() {
console.log('🔄 Signature module initializing...');
// Получаем текущего пользователя и проверяем, является ли он подписантом
await getCurrentUser();
// Добавляем кнопки на существующие карточки только если пользователь подписант
setTimeout(() => {
if (isCurrentUserSigner) {
window.addSignatureButtons();
}
}, 1000);
// Запускаем наблюдение за DOM
observeDOM();
// Перехватываем функцию рендеринга TasksType если она существует
if (window.TasksType && window.TasksType.renderExpandedContent) {
const originalRender = window.TasksType.renderExpandedContent;
window.TasksType.renderExpandedContent = function(task) {
let html = originalRender ? originalRender(task) : '';
// Добавляем кнопку подписания в развернутое содержимое только для документов и если пользователь подписант
if (currentUser && isCurrentUserSigner && task.task_type === CONFIG.taskTypeDocument) {
// Создаем контейнер action-buttons если его нет
if (!html.includes('action-buttons')) {
const signButton = `
<div class="action-buttons" style="margin-bottom: 10px;">
<button class="action-btn sign-btn" onclick="signTask(${task.id}, ${currentUser.id})" title="Передать подписанту">
✍️ Подписать
</button>
</div>
`;
// Вставляем кнопки после заголовка
html = html.replace('<div class="tasks-type-header">',
'<div class="tasks-type-header">' + signButton);
} else {
// Добавляем кнопку в существующий контейнер
const signButton = `
<button class="action-btn sign-btn" onclick="signTask(${task.id}, ${currentUser.id})" title="Передать подписанту">
✍️ Подписать
</button>
`;
html = html.replace('</div><div class="tasks-type-description">',
signButton + '</div><div class="tasks-type-description">');
}
}
return html;
};
}
console.log('✅ Signature module loaded. User is signer:', isCurrentUserSigner);
}
// Запускаем инициализацию после загрузки DOM
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();