- 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
128 lines
4.4 KiB
JavaScript
128 lines
4.4 KiB
JavaScript
/**
|
||
* @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;
|
||
}
|