Corp/backend/static/js/components/documentAcknowledgeHandler.js
Игорь Надеин 35f365a1b0 feat: Add department-based document distribution with department picker in UI
- Added departments ManyToMany field to Document model
- Implemented department selection in document create/edit modals
- Added automatic notification creation for all department employees
- Fixed document filtering to include uploaded documents in 'My Documents'
- Fixed acknowledgements API to include department recipients
- Added bulk notification support with configurable threshold
- Removed acknowledge button, added visual highlighting for unread documents
- Implemented server-side acknowledgment flow with redirect to file
- Fixed mobile responsive layout for document actions
- Removed temporary test files and documentation
2025-11-21 12:46:43 +03:00

128 lines
4.4 KiB
JavaScript
Raw Permalink 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.

/**
* @module documentAcknowledgeHandler
* @description Обработчик автоматического ознакомления с документами.
* При клике на неознакомленный документ автоматически отправляет POST запрос
* на /api/v1/documents/{id}/acknowledge/ и обновляет UI.
*
* Использование:
* import { initDocumentAcknowledge } from './documentAcknowledgeHandler.js';
*
* initDocumentAcknowledge({
* apiDetailBase: '/api/v1/documents/',
* headers: { 'Authorization': 'Bearer TOKEN' }
* });
*/
/**
* Инициализирует обработчик автоматического ознакомления с документами.
* @param {Object} options - Опции инициализации
* @param {string} options.apiDetailBase - Базовый URL для API документов
* @param {Object} [options.headers={}] - HTTP заголовки для запросов
* @returns {Object} API с методом destroy
*/
export function initDocumentAcknowledge(options) {
const {
apiDetailBase,
headers = {}
} = options;
const listElement = document.getElementById('docList');
if (!listElement) {
console.warn('initDocumentAcknowledge: элемент #docList не найден');
return { destroy: () => {} };
}
/**
* Отправляет ознакомление на сервер.
* @param {number} docId - ID документа
* @returns {Promise<boolean>} - true если успешно
*/
async function acknowledgeDocument(docId) {
try {
const response = await fetch(`${apiDetailBase}${docId}/acknowledge/`, {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json'
}
});
if (response.ok || response.status === 201) {
return true;
} else {
console.error('Не удалось отметить ознакомление:', response.status);
return false;
}
} catch (error) {
console.error('Ошибка при отправке ознакомления:', error);
return false;
}
}
/**
* Обновляет UI документа после ознакомления.
* @param {HTMLElement} docRow - Элемент строки документа
*/
function updateDocumentUI(docRow) {
// Убираем класс неознакомленного
docRow.classList.remove('doc-unacked');
// Обновляем data-атрибут
docRow.dataset.isAcked = '1';
// Добавляем бейдж "Ознакомлен" если его еще нет
const actions = docRow.querySelector('.doc-actions');
if (actions && !actions.querySelector('.badge-acked')) {
const badge = document.createElement('span');
badge.className = 'badge-acked';
badge.textContent = '✓ Ознакомлен';
actions.insertBefore(badge, actions.firstChild);
}
}
/**
* Обработчик клика по документу.
*/
async function handleDocumentClick(e) {
// Проверяем, что клик был по ссылке на документ
const link = e.target.closest('.doc-link');
if (!link) return;
const docId = link.dataset.docId;
if (!docId) return;
// Находим строку документа
const docRow = link.closest('.doc-row');
if (!docRow) return;
// Проверяем, не ознакомлен ли уже
const isAcked = docRow.dataset.isAcked === '1';
if (isAcked) return; // Уже ознакомлен, ничего не делаем
// Отправляем ознакомление асинхронно (не блокируем открытие файла)
acknowledgeDocument(docId).then(success => {
if (success) {
updateDocumentUI(docRow);
}
});
}
// Установка обработчика
listElement.addEventListener('click', handleDocumentClick);
/**
* Функция для удаления обработчика.
*/
function destroy() {
listElement.removeEventListener('click', handleDocumentClick);
}
return { destroy };
}
// Экспорт для совместимости с неModular кодом
if (typeof window !== 'undefined') {
window.initDocumentAcknowledge = initDocumentAcknowledge;
}