ℹ модальное окно с деталями парсинга (параграфы, таблицы, ошибки, превью), v1.10

This commit is contained in:
2026-06-17 07:19:38 +04:00
parent 4474190cae
commit f627572abb
2 changed files with 110 additions and 5 deletions
+91 -3
View File
@@ -42,12 +42,25 @@
.empty-row td { color: var(--muted); text-align: center; padding: 24px; }
.remove-btn { cursor: pointer; color: var(--muted); background: none; border: none; padding: 2px 4px; font-size: 16px; line-height: 1; }
.remove-btn:hover { color: var(--destructive); }
.info-btn { cursor: pointer; color: var(--muted); background: none; border: none; padding: 2px 4px; font-size: 14px; display: none; }
.info-btn:hover { color: var(--brand-primary); }
.info-btn.visible { display: inline; }
/* Modal */
.modal-overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,.4); z-index: 100; justify-content: center; align-items: center; }
.modal-overlay.open { display: flex; }
.modal { background: var(--background); border-radius: 12px; border: 1px solid var(--brand-gray); box-shadow: 0 4px 24px rgba(0,0,0,.15); max-width: 520px; width: 90%; max-height: 80vh; overflow-y: auto; }
.modal-header { padding: 14px 16px; border-bottom: 1px solid var(--brand-gray); display: flex; align-items: center; gap: 8px; font-weight: 600; }
.modal-body { padding: 16px; }
.modal-body .kv { display: flex; margin-bottom: 6px; font-size: 13px; }
.modal-body .kv .k { color: var(--muted); width: 110px; flex-shrink: 0; }
.modal-body .kv .v { word-break: break-all; }
.modal-body pre { background: var(--brand-grey-light); padding: 10px; border-radius: 6px; font-size: 12px; max-height: 200px; overflow-y: auto; white-space: pre-wrap; margin-top: 4px; }
</style>
</head>
<body>
<div class="topbar">
<img src="{{ url_for('static', filename='nubes-logo.svg') }}" alt="Nubes">
<span class="title">Сверка договоров <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.9</span></span>
<span class="title">Сверка договоров <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.10</span></span>
</div>
<div class="content">
@@ -62,7 +75,7 @@
<div class="table-wrap">
<table>
<thead>
<tr><th>Имя</th><th style="width:130px;">Изменён</th><th style="width:90px;">Размер</th><th style="width:115px;">Статус</th><th style="width:30px;"></th></tr>
<tr><th>Имя</th><th style="width:130px;">Изменён</th><th style="width:90px;">Размер</th><th style="width:115px;">Статус</th><th style="width:55px;"></th></tr>
</thead>
<tbody id="fileTable"></tbody>
</table>
@@ -75,6 +88,18 @@
</div>
</div>
<!-- Модальное окно Инфо -->
<div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
<div class="modal" onclick="event.stopPropagation()">
<div class="modal-header">
<i data-lucide="file-text" style="width:18px;height:18px;"></i>
<span id="modalTitle">Информация о файле</span>
<button class="remove-btn" onclick="closeModal()" style="margin-left:auto;font-size:18px;">×</button>
</div>
<div class="modal-body" id="modalBody"></div>
</div>
</div>
<script>
lucide.createIcons();
@@ -110,7 +135,8 @@
'<td style="font-size:12px;color:var(--muted);">' + formatDate(f.lastModified) + '</td>' +
'<td class="num-cell" style="font-size:12px;color:var(--muted);">' + formatSize(f.size) + '</td>' +
'<td class="status-cell"></td>' +
'<td><button class="remove-btn" onclick="removeFile(' + i + ')" title="Удалить">×</button></td>' +
'<td><button class="remove-btn" onclick="removeFile(' + i + ')" title="Удалить">×</button>' +
'<button class="info-btn" id="info_' + i + '" onclick="showInfo(' + i + ')" title="Инфо"></button></td>' +
'</tr>';
}).join('');
}
@@ -290,6 +316,13 @@
var row = findRowByName(d.name);
if (row) {
row.querySelector('.status-cell').innerHTML = '<span class="status-ok">✓ ' + d.time_s + 'с</span>';
// Сохранить детали в fileQueue и показать ℹ
var idx = findIndexByName(d.name);
if (idx >= 0) {
fileQueue[idx].parseInfo = d;
var infoBtn = document.getElementById('info_' + idx);
if (infoBtn) infoBtn.classList.add('visible');
}
}
}
@@ -347,8 +380,63 @@
}
return null;
}
function findIndexByName(name) {
for (var i = 0; i < fileQueue.length; i++) {
if (fileQueue[i].name === name) return i;
}
return -1;
}
});
// ── Модальное окно ──────────────────────────────────────────
function showInfo(index) {
var f = fileQueue[index];
if (!f || !f.parseInfo) return;
var d = f.parseInfo;
document.getElementById('modalTitle').textContent = f.name;
var rows = [
['Тип', f.file ? f.file.type : (f.name.split('.').pop() || '—')],
['Размер', formatSize(f.size)],
['В архиве', f.zipName || '—'],
['Статус', 'parsed'],
['Время парсинга', d.time_s + 'с'],
['Элементов всего', d.elements],
['Параграфов', d.paragraphs],
['Таблиц', d.tables],
['Строк таблиц', d.table_rows],
['Текст (символов)', d.text_len],
];
var html = rows.map(function(r) {
return '<div class="kv"><span class="k">' + r[0] + '</span><span class="v">' + r[1] + '</span></div>';
}).join('');
if (d.errors && d.errors.length > 0) {
html += '<div style="margin-top:8px;color:var(--destructive);font-weight:600;">Ошибки парсера:</div>';
html += '<pre>' + d.errors.join('\n') + '</pre>';
}
if (d.text_preview) {
html += '<div style="margin-top:10px;font-weight:600;font-size:13px;">Превью текста:</div>';
html += '<pre>' + d.text_preview + '</pre>';
}
document.getElementById('modalBody').innerHTML = html;
document.getElementById('modalOverlay').classList.add('open');
}
function closeModal(e) {
if (e && e.target !== document.getElementById('modalOverlay')) return;
document.getElementById('modalOverlay').classList.remove('open');
}
window.showInfo = showInfo;
window.closeModal = closeModal;
var style = document.createElement('style');
style.textContent = '@keyframes spin { to { transform: rotate(360deg); } }';
document.head.appendChild(style);