// popup.js (function () { // Состояние фильтров let filters = { esia: 'all', sender: 'all', status: 'all', period: 'today' }; let filtersChanged = false; let allStatuses = []; let currentUserId = null; // DOM элементы const authWarning = document.getElementById('authWarning'); const tableSection = document.getElementById('tableSection'); const tableBody = document.getElementById('tableBody'); const emptyState = document.getElementById('emptyState'); const refreshBtn = document.getElementById('refreshBtn'); const searchInput = document.getElementById('searchInput'); const searchClear = document.getElementById('searchClear'); const allDocumentsBtn = document.getElementById('allDocumentsBtn'); // Фильтры const esiaFilter = document.getElementById('esiaFilter'); const senderFilter = document.getElementById('senderFilter'); const statusFilter = document.getElementById('statusFilter'); const periodFilter = document.getElementById('periodFilter'); // Настройки сервера const serverAccordion = document.getElementById('serverAccordion'); const accordionHeader = document.getElementById('accordionHeader'); const accordionIcon = document.getElementById('accordionIcon'); const accordionTitle = document.getElementById('accordionTitle'); const currentServerIp = document.getElementById('currentServerIp'); const currentServerPort = document.getElementById('currentServerPort'); const editServerIp = document.getElementById('editServerIp'); const editServerPort = document.getElementById('editServerPort'); const viewButtons = document.getElementById('viewButtons'); const editButtons = document.getElementById('editButtons'); const editButton = document.getElementById('editButton'); const adminButton = document.getElementById('adminButton'); const saveOptions = document.getElementById('saveOptions'); const cancelOptions = document.getElementById('cancelOptions'); // Вспомогательные функции function formatDate(dateString) { const date = new Date(dateString); return date.toLocaleString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); } function getStatusClass(category) { switch (category) { case 'completed': return 'status-completed'; case 'processing': return 'status-processing'; case 'error': return 'status-error'; default: return 'status-waiting'; } } function getStatusIcon(category) { switch (category) { case 'completed': return '✅'; case 'processing': return '⌛'; case 'error': return '❌'; default: return '?'; } } function showMessage(message, type = 'success', duration = 2000) { const messageEl = document.createElement('div'); messageEl.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 10000; padding: 8px 16px; border-radius: 4px; background: ${type === 'success' ? '#f0f9eb' : '#fef0f0'}; border: 1px solid ${type === 'success' ? '#e1f3d8' : '#fde2e2'}; color: ${type === 'success' ? '#67c23a' : '#f56c6c'}; font-size: 13px; box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1); `; messageEl.textContent = message; document.body.appendChild(messageEl); setTimeout(() => messageEl.remove(), duration); } // Функция для выделения кнопки обновления function highlightRefreshButton() { refreshBtn.style.animation = 'pulse 1.5s infinite'; refreshBtn.style.backgroundColor = '#e6f7ff'; refreshBtn.style.borderColor = '#91d5ff'; } function resetRefreshButton() { refreshBtn.style.animation = 'none'; refreshBtn.style.backgroundColor = ''; refreshBtn.style.borderColor = ''; } // Добавляем стили const style = document.createElement('style'); style.textContent = ` @keyframes pulse { 0% { transform: scale(1); background-color: #ffffff; } 50% { transform: scale(1.05); background-color: #e6f7ff; box-shadow: 0 0 10px rgba(64, 158, 255, 0.5); } 100% { transform: scale(1); background-color: #ffffff; } } .clickable-doc { cursor: pointer; transition: opacity 0.2s; } .clickable-doc:hover { opacity: 0.8; background-color: #f0f9eb !important; } .doc-view-btn { margin-left: 4px; padding: 2px 6px; border: none; background: #ecf5ff; color: #409eff; border-radius: 3px; font-size: 11px; cursor: pointer; display: inline-flex; align-items: center; gap: 2px; } .doc-view-btn:hover { background: #d9ecff; } .status-container { max-width: 140px; } .document-status { max-width: 140px; word-break: break-word; } .doctor-name { font-size: 10px; color: #909399; margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 140px; } `; document.head.appendChild(style); // Отправка сообщений в background async function sendMessageToBackground(action, data) { return new Promise((resolve) => { chrome.runtime.sendMessage({ action, data }, (response) => { resolve(response || { success: false, message: 'Нет ответа от background' }); }); }); } // Сохранение фильтров в storage function saveFiltersToStorage() { chrome.storage.local.set({ documentFilters: filters }); } // Загрузка фильтров из storage async function loadFiltersFromStorage() { return new Promise((resolve) => { chrome.storage.local.get(['documentFilters'], (result) => { if (result.documentFilters) { filters = { ...filters, ...result.documentFilters }; // Применяем фильтры к элементам управления esiaFilter.value = filters.esia; senderFilter.value = filters.sender; statusFilter.value = filters.status; periodFilter.value = filters.period; } resolve(); }); }); } // Получение статусов с сервера async function loadStatuses() { try { refreshBtn.disabled = true; refreshBtn.innerHTML = '🔄 Загрузка...'; // Получаем ID пользователя из storage await getCurrentUserId(); // Если нет ID пользователя - считаем что не авторизованы if (!currentUserId) { authWarning.classList.add('visible'); tableSection.classList.remove('visible'); return; } // Формируем данные для отправки на сервер (без search) const requestData = { userIdLpu: currentUserId, filters: { esia: filters.esia, sender: filters.sender, status: filters.status, period: filters.period } }; // Отправляем запрос с фильтрами const response = await sendMessageToBackground('getStatuses', requestData); if (response.success && Array.isArray(response.data)) { allStatuses = response.data; authWarning.classList.remove('visible'); tableSection.classList.add('visible'); // Применяем поиск на клиенте applyClientFilters(); } else { showMessage('Ошибка загрузки: ' + (response.message || 'Неизвестная ошибка'), 'error'); allStatuses = []; renderTable([]); } } catch (error) { showMessage('Ошибка загрузки данных', 'error'); allStatuses = []; renderTable([]); } finally { refreshBtn.disabled = false; refreshBtn.innerHTML = '🔄 Обновить'; resetRefreshButton(); filtersChanged = false; } } // Получение ID текущего пользователя из storage async function getCurrentUserId() { return new Promise((resolve) => { chrome.storage.local.get(['userData'], (result) => { if (result.userData && result.userData.id) { currentUserId = result.userData.id; resolve(currentUserId); } else { currentUserId = null; resolve(null); } }); }); } // Применение клиентских фильтров (поиск) function applyClientFilters() { let filtered = [...allStatuses]; // Поиск по тексту (на клиенте) const searchText = searchInput.value.toLowerCase().trim(); if (searchText) { filtered = filtered.filter(item => { const patientName = (item.patientName || '').toLowerCase(); const documents = item.documents?.map(d => `${d.number} ${d.title}`).join(' ').toLowerCase() || ''; return patientName.includes(searchText) || documents.includes(searchText); }); } renderTable(filtered); } // Просмотр документа async function viewDocument(documentPath, title) { try { const response = await sendMessageToBackground('getDocument', { documentPath }); if (response.success && response.data) { const byteCharacters = atob(response.data); const byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: 'application/pdf' }); const url = window.URL.createObjectURL(blob); const newWindow = window.open(url, '_blank'); if (!newWindow) { const link = document.createElement('a'); link.href = url; link.download = 'document.pdf'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } setTimeout(() => window.URL.revokeObjectURL(url), 1000); } else { showMessage('Ошибка загрузки документа', 'error'); } } catch (error) { showMessage('Ошибка просмотра документа', 'error'); } } // Рендер таблицы // Рендер таблицы function renderTable(data) { if (!data || data.length === 0) { tableBody.innerHTML = ''; emptyState.classList.remove('hidden'); return; } emptyState.classList.add('hidden'); const rows = data.map(item => { // Берем только общие статусы (где idPatientMis === null) const commonStatuses = item.statuses?.filter(s => s.idPatientMis === null) || []; // Берем последний общий статус const lastStatus = commonStatuses.length > 0 ? commonStatuses.reduce((max, s) => s.id > max.id ? s : max, commonStatuses[0]) : null; // Если нет общих статусов, используем первый статус из списка как fallback const displayStatus = lastStatus || (item.statuses && item.statuses[0]) || null; const statusClass = getStatusClass(displayStatus?.category); const statusIcon = getStatusIcon(displayStatus?.category); // Маппинг типов доставки на отображаемые названия const deliveryTypeLabels = { 'sms': 'СМС', 'max': 'МАХ', 'mila': 'Mila', 'goskey': 'Goskey' }; const documentsHtml = item.documents?.map(doc => { // Документы можно просматривать только если статус не error const isClickable = displayStatus?.category !== 'error' && doc.storagePath; const baseClass = isClickable ? 'doc-item clickable-doc' : 'doc-item'; return `