v1.0.78: один столбец Текст вместо View/Инфо, левая=textify, правая=распарсено
This commit is contained in:
@@ -61,7 +61,7 @@
|
|||||||
.text-pane { flex: 1; min-width: 0; overflow-y: auto; max-height: 65vh; }
|
.text-pane { flex: 1; min-width: 0; overflow-y: auto; max-height: 65vh; }
|
||||||
.text-pane:first-child { border-right: 1px solid var(--brand-gray); padding-right: 12px; }
|
.text-pane:first-child { border-right: 1px solid var(--brand-gray); padding-right: 12px; }
|
||||||
.text-pane:last-child { padding-left: 12px; }
|
.text-pane:last-child { padding-left: 12px; }
|
||||||
.text-pane pre { background: var(--brand-grey-light); padding: 10px; border-radius: 6px; font-size: 11px; white-space: pre-wrap; margin: 0; }
|
.text-pane pre { background: var(--brand-grey-light); padding: 10px; border-radius: 6px; font-size: 11px; white-space: pre-wrap; word-break: break-word; overflow-x: auto; margin: 0; max-height: 60vh; overflow-y: auto; }
|
||||||
.text-pane table { font-size: 11px; width: 100%; }
|
.text-pane table { font-size: 11px; width: 100%; }
|
||||||
.text-pane th { font-size: 10px; padding: 4px 6px; }
|
.text-pane th { font-size: 10px; padding: 4px 6px; }
|
||||||
.text-pane td { padding: 3px 6px; font-size: 11px; }
|
.text-pane td { padding: 3px 6px; font-size: 11px; }
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<img src="/nubes-logo.svg" alt="Nubes">
|
<img src="/nubes-logo.svg" alt="Nubes">
|
||||||
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.77 — Lucee</span></span>
|
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.78 — Lucee</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -86,16 +86,12 @@
|
|||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Имя</th><th style="width:130px;">Изменён</th><th style="width:90px;">Размер</th><th style="width:115px;">Парсинг</th><th style="width:30px;">Базовый</th><th style="width:30px;">View</th><th style="width:30px;">Текст</th><th style="width:30px;">Инфо</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:30px;">Базовый</th><th style="width:30px;">Текст</th><th style="width:30px;">✕</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="fileTable"></tbody>
|
<tbody id="fileTable"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary" id="parseBtn" style="width:100%;justify-content:center;margin-top:12px;" disabled>
|
|
||||||
<i data-lucide="play" style="width:16px;height:16px;"></i> Парсинг
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-primary" id="llmBtn" style="width:100%;justify-content:center;margin-top:8px;display:none;">
|
<button class="btn btn-primary" id="llmBtn" style="width:100%;justify-content:center;margin-top:8px;display:none;">
|
||||||
<i data-lucide="scale" style="width:16px;height:16px;"></i> Сравнить (LLM)
|
<i data-lucide="scale" style="width:16px;height:16px;"></i> Сравнить (LLM)
|
||||||
</button>
|
</button>
|
||||||
@@ -158,7 +154,6 @@ var CONVERT_URL = 'https://contracts.kube5s.ru/convert-doc';
|
|||||||
var SITE_URL = ''; // same origin for api calls
|
var SITE_URL = ''; // same origin for api calls
|
||||||
|
|
||||||
var fileInput = document.getElementById('fileInput');
|
var fileInput = document.getElementById('fileInput');
|
||||||
var parseBtn = document.getElementById('parseBtn');
|
|
||||||
var fileTable = document.getElementById('fileTable');
|
var fileTable = document.getElementById('fileTable');
|
||||||
var fileQueue = [];
|
var fileQueue = [];
|
||||||
var contractId = null;
|
var contractId = null;
|
||||||
@@ -178,8 +173,7 @@ function formatDate(ts) {
|
|||||||
|
|
||||||
function renderTable() {
|
function renderTable() {
|
||||||
if (fileQueue.length === 0) {
|
if (fileQueue.length === 0) {
|
||||||
fileTable.innerHTML = '<tr class="empty-row"><td colspan="8">Нет файлов — выберите .docx / .pdf / .zip</td></tr>';
|
fileTable.innerHTML = '<tr class="empty-row"><td colspan="7">Нет файлов — выберите .docx / .pdf / .zip</td></tr>';
|
||||||
parseBtn.disabled = true;
|
|
||||||
} else {
|
} else {
|
||||||
fileTable.innerHTML = fileQueue.map(function(f, i) {
|
fileTable.innerHTML = fileQueue.map(function(f, i) {
|
||||||
var radio = '';
|
var radio = '';
|
||||||
@@ -192,9 +186,7 @@ function renderTable() {
|
|||||||
'<td class="num-cell" style="font-size:12px;color:var(--muted);">' + formatSize(f.size) + '</td>' +
|
'<td class="num-cell" style="font-size:12px;color:var(--muted);">' + formatSize(f.size) + '</td>' +
|
||||||
'<td class="status-cell">' + (f.status || '') + '</td>' +
|
'<td class="status-cell">' + (f.status || '') + '</td>' +
|
||||||
'<td style="text-align:center;">' + radio + '</td>' +
|
'<td style="text-align:center;">' + radio + '</td>' +
|
||||||
'<td><button class="info-btn' + (f.doc_id ? ' visible' : '') + '" onclick="showView(\'' + (f.doc_id||'') + '\')" title="Просмотр"><i data-lucide="eye" style="width:16px;height:16px;"></i></button></td>' +
|
'<td><button class="info-btn' + (f.doc_id ? ' visible' : '') + '" onclick="showText(' + i + ')" title="Текст / Распарсено"><i data-lucide="file-text" style="width:16px;height:16px;"></i></button></td>' +
|
||||||
'<td><button class="info-btn' + (f.doc_id ? ' visible' : '') + '" onclick="showText(\'' + (f.doc_id||'') + '\')" title="Текст / Распарсено"><i data-lucide="file-text" style="width:16px;height:16px;"></i></button></td>' +
|
|
||||||
'<td><button class="info-btn' + (f.doc_id ? ' visible' : '') + '" id="info_' + i + '" onclick="showInfo(' + i + ')" title="Инфо"><i data-lucide="info" style="width:16px;height:16px;"></i></button></td>' +
|
|
||||||
'<td><button class="remove-btn" onclick="removeFile(' + i + ')" title="Удалить"><i data-lucide="trash-2" style="width:16px;height:16px;"></i></button></td>' +
|
'<td><button class="remove-btn" onclick="removeFile(' + i + ')" title="Удалить"><i data-lucide="trash-2" style="width:16px;height:16px;"></i></button></td>' +
|
||||||
'</tr>';
|
'</tr>';
|
||||||
}).join('');
|
}).join('');
|
||||||
@@ -215,8 +207,6 @@ fileInput.addEventListener('change', async function() {
|
|||||||
if (newFiles.length === 0) return;
|
if (newFiles.length === 0) return;
|
||||||
|
|
||||||
fileInput.disabled = true;
|
fileInput.disabled = true;
|
||||||
parseBtn.disabled = true;
|
|
||||||
parseBtn.innerHTML = '<span class="spinner"></span> Загрузка...';
|
|
||||||
|
|
||||||
for (var i = 0; i < newFiles.length; i++) {
|
for (var i = 0; i < newFiles.length; i++) {
|
||||||
var f = newFiles[i];
|
var f = newFiles[i];
|
||||||
@@ -264,8 +254,6 @@ fileInput.addEventListener('change', async function() {
|
|||||||
|
|
||||||
fileInput.value = '';
|
fileInput.value = '';
|
||||||
fileInput.disabled = false;
|
fileInput.disabled = false;
|
||||||
parseBtn.disabled = false;
|
|
||||||
parseBtn.innerHTML = '<i data-lucide="play" style="width:16px;height:16px;"></i> Парсинг';
|
|
||||||
// Показать кнопки LLM после авто-парсинга
|
// Показать кнопки LLM после авто-парсинга
|
||||||
var llmBtn = document.getElementById('llmBtn');
|
var llmBtn = document.getElementById('llmBtn');
|
||||||
llmBtn.style.display = 'flex';
|
llmBtn.style.display = 'flex';
|
||||||
@@ -326,47 +314,6 @@ function uploadFile(file, onProgress) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Парсинг ──────────────────────────────────────────────────
|
|
||||||
parseBtn.addEventListener('click', async function() {
|
|
||||||
if (!contractId) return;
|
|
||||||
parseBtn.disabled = true;
|
|
||||||
parseBtn.innerHTML = '<span class="spinner"></span> Парсинг...';
|
|
||||||
|
|
||||||
for (var i = 0; i < fileQueue.length; i++) {
|
|
||||||
var f = fileQueue[i];
|
|
||||||
if (!f.doc_id || f.parsed) continue;
|
|
||||||
f.status = '⏳';
|
|
||||||
renderTable();
|
|
||||||
try {
|
|
||||||
var resp = await fetch('/parser.cfm?doc_id=' + f.doc_id);
|
|
||||||
var d = await resp.json();
|
|
||||||
if (d.OK && d.STATUS === 'parsed') {
|
|
||||||
f.parsed = true;
|
|
||||||
f.parseInfo = d;
|
|
||||||
f.status = '<span class="status-ok">✓ ' + d.ELEMENT_COUNT + ' эл.</span>';
|
|
||||||
} else {
|
|
||||||
f.status = '<span class="status-err">✗ ' + (d.ERROR_COUNT > 0 ? (d.ERRORS && d.ERRORS[0] || 'ошибка') : 'ошибка') + '</span>';
|
|
||||||
f.parseInfo = d;
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
f.status = '<span class="status-err">✗ сеть</span>';
|
|
||||||
}
|
|
||||||
renderTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обновить информацию о supplement_id/type для radio
|
|
||||||
await refreshSupps();
|
|
||||||
|
|
||||||
parseBtn.innerHTML = '<i data-lucide="check" style="width:16px;height:16px;"></i> ✓ Готово';
|
|
||||||
var llmBtn = document.getElementById('llmBtn');
|
|
||||||
llmBtn.style.display = 'flex';
|
|
||||||
llmBtn.disabled = false;
|
|
||||||
var llmBtnV2 = document.getElementById('llmBtnV2');
|
|
||||||
llmBtnV2.style.display = 'flex';
|
|
||||||
llmBtnV2.disabled = false;
|
|
||||||
lucide.createIcons();
|
|
||||||
});
|
|
||||||
|
|
||||||
// ── LLM v2: Event Sourcing ─────────────────────────────────
|
// ── LLM v2: Event Sourcing ─────────────────────────────────
|
||||||
document.getElementById('llmBtnV2').addEventListener('click', function() {
|
document.getElementById('llmBtnV2').addEventListener('click', function() {
|
||||||
if (!contractId) return;
|
if (!contractId) return;
|
||||||
@@ -600,132 +547,96 @@ document.getElementById('chatInput').addEventListener('keydown', function(e) {
|
|||||||
if (e.key === 'Enter') document.getElementById('chatSend').click();
|
if (e.key === 'Enter') document.getElementById('chatSend').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Инфо ─────────────────────────────────────────────────────
|
|
||||||
function showInfo(i) {
|
|
||||||
var f = fileQueue[i];
|
|
||||||
document.getElementById('modalTitle').textContent = f.name;
|
|
||||||
var html = '<div class="kv"><span class="k">Размер</span><span class="v">' + formatSize(f.size) + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Изменён</span><span class="v">' + formatDate(f.lastModified) + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Тип</span><span class="v">' + (f.type || '—') + '</span></div>';
|
|
||||||
if (f.parseInfo) {
|
|
||||||
var d = f.parseInfo;
|
|
||||||
html += '<div class="kv"><span class="k">Элементов</span><span class="v">' + (d.ELEMENT_COUNT||0) + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Параграфов</span><span class="v">' + (d.PARAGRAPHS||0) + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Таблиц</span><span class="v">' + (d.TABLES||0) + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Строк таблиц</span><span class="v">' + (d.TABLE_ROWS||0) + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Страниц</span><span class="v">' + (d.PAGES||'—') + '</span></div>';
|
|
||||||
if (d.PARSE_TIME_MS) {
|
|
||||||
html += '<div class="kv"><span class="k">Время парсинга</span><span class="v">' + (d.PARSE_TIME_MS > 1000 ? (d.PARSE_TIME_MS/1000).toFixed(1) + ' с' : d.PARSE_TIME_MS + ' мс') + '</span></div>';
|
|
||||||
}
|
|
||||||
if (d.TEXT_LENGTH) {
|
|
||||||
html += '<div class="kv"><span class="k">Символов текста</span><span class="v">' + d.TEXT_LENGTH.toLocaleString() + '</span></div>';
|
|
||||||
}
|
|
||||||
if (d.TEXT_PREVIEW) {
|
|
||||||
html += '<div style="margin-top:10px;font-weight:600;font-size:13px;">Превью текста (первые 3000 симв.):</div>';
|
|
||||||
html += '<pre style="max-height:200px;overflow-y:auto;">' + d.TEXT_PREVIEW.substring(0, 3000) + '</pre>';
|
|
||||||
}
|
|
||||||
if (d.TABLE_HEADERS && d.TABLE_HEADERS.length > 0) {
|
|
||||||
html += '<div style="margin-top:10px;font-weight:600;font-size:13px;">Заголовки таблиц:</div>';
|
|
||||||
d.TABLE_HEADERS.forEach(function(hdr, ti) {
|
|
||||||
html += '<div style="margin-top:4px;font-size:11px;color:var(--muted);">Таблица ' + (ti+1) + ' (' + (hdr||[]).length + ' колонок):</div>';
|
|
||||||
html += '<pre>' + (hdr||[]).map(function(c){return c||'(пусто)';}).join(' | ') + '</pre>';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (d.TABLE_SAMPLES && d.TABLE_SAMPLES.length > 0) {
|
|
||||||
html += '<div style="margin-top:10px;font-weight:600;font-size:13px;">Первые строки таблиц:</div>';
|
|
||||||
d.TABLE_SAMPLES.forEach(function(sample, ti) {
|
|
||||||
html += '<div style="margin-top:4px;font-size:11px;color:var(--muted);">Таблица ' + (ti+1) + ':</div>';
|
|
||||||
html += '<pre style="max-height:120px;overflow-y:auto;">' + sample.map(function(row){ return (row||[]).map(function(c){return c||'(пусто)';}).join(' | '); }).join('\n') + '</pre>';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
html += '<div class="kv"><span class="k">doc_id</span><span class="v">' + (f.doc_id || '—') + '</span></div>';
|
|
||||||
if (f.supp_id) {
|
|
||||||
html += '<div class="kv"><span class="k">supp_id</span><span class="v">' + f.supp_id + '</span></div>';
|
|
||||||
html += '<div class="kv"><span class="k">Тип ДС</span><span class="v">' + (f.supp_type || '—') + '</span></div>';
|
|
||||||
}
|
|
||||||
document.getElementById('modalBody').innerHTML = html;
|
|
||||||
document.getElementById('modalOverlay').classList.add('open');
|
|
||||||
}
|
|
||||||
function closeModal(e) {
|
function closeModal(e) {
|
||||||
if (e && e.target !== document.getElementById('modalOverlay')) return;
|
if (e && e.target !== document.getElementById('modalOverlay')) return;
|
||||||
|
document.querySelector('.modal').classList.remove('wide');
|
||||||
document.getElementById('modalOverlay').classList.remove('open');
|
document.getElementById('modalOverlay').classList.remove('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showView(docId) {
|
async function showText(i) {
|
||||||
document.getElementById('modalTitle').textContent = 'Просмотр документа';
|
var f = fileQueue[i];
|
||||||
document.getElementById('modalBody').innerHTML = '<span style="color:var(--muted);">Загрузка...</span>';
|
var docId = f.doc_id;
|
||||||
document.getElementById('modalOverlay').classList.add('open');
|
document.getElementById('modalTitle').textContent = f.name;
|
||||||
try {
|
|
||||||
var resp = await fetch('/view.cfm?doc_id=' + docId);
|
|
||||||
var text = await resp.text();
|
|
||||||
document.getElementById('modalBody').innerHTML = '<pre style="background:var(--brand-grey-light);padding:12px;border-radius:6px;font-size:12px;max-height:60vh;overflow-y:auto;white-space:pre-wrap;margin:0;">' + text.replace(/</g,'<').replace(/>/g,'>') + '</pre>';
|
|
||||||
} catch(e) {
|
|
||||||
document.getElementById('modalBody').innerHTML = '<span style="color:var(--destructive);">Ошибка загрузки</span>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showText(docId) {
|
|
||||||
document.getElementById('modalTitle').textContent = 'Текст / Распарсено';
|
|
||||||
document.getElementById('modalBody').innerHTML = '<span style="color:var(--muted);">Загрузка...</span>';
|
document.getElementById('modalBody').innerHTML = '<span style="color:var(--muted);">Загрузка...</span>';
|
||||||
var modal = document.querySelector('.modal');
|
var modal = document.querySelector('.modal');
|
||||||
modal.classList.add('wide');
|
modal.classList.add('wide');
|
||||||
document.getElementById('modalOverlay').classList.add('open');
|
document.getElementById('modalOverlay').classList.add('open');
|
||||||
|
|
||||||
|
// Левая панель: сырой текст
|
||||||
|
var leftHtml = '<span style="color:var(--muted);">Загрузка...</span>';
|
||||||
|
if (docId) {
|
||||||
try {
|
try {
|
||||||
var resp = await fetch('/view.cfm?doc_id=' + docId);
|
var vResp = await fetch('/view.cfm?doc_id=' + docId);
|
||||||
var rawText = await resp.text();
|
var rawText = await vResp.text();
|
||||||
// Clean leading whitespace from CFML
|
|
||||||
rawText = rawText.replace(/^\s+/, '');
|
rawText = rawText.replace(/^\s+/, '');
|
||||||
// Fetch parsed elements via API
|
leftHtml = '<pre>' + rawText.replace(/</g,'<').replace(/>/g,'>') + '</pre>';
|
||||||
var qResp = await fetch('/api.cfm?action=query&sql=SELECT%20elements_json%20FROM%20documents%20WHERE%20id%3D\'' + docId + '\'');
|
} catch(e) {
|
||||||
var qData = await qResp.json();
|
leftHtml = '<span style="color:var(--destructive);">Ошибка</span>';
|
||||||
var parsedHtml = '<span style="color:var(--muted);">Нет данных парсинга</span>';
|
|
||||||
if (qData.OK && qData.ROWS && qData.ROWS.length > 0) {
|
|
||||||
var ej = qData.ROWS[0].ELEMENTS_JSON;
|
|
||||||
if (typeof ej === 'object' && ej.Value) ej = ej.Value;
|
|
||||||
var elements = JSON.parse(ej);
|
|
||||||
if (elements.length > 0) {
|
|
||||||
var rows = '';
|
|
||||||
elements.forEach(function(el, idx) {
|
|
||||||
var etype = el.type || el.TYPE || '?';
|
|
||||||
var style = el.style || el.STYLE || '';
|
|
||||||
var content = '';
|
|
||||||
if (etype === 'paragraph') {
|
|
||||||
content = (el.text || el.TEXT || '').substring(0, 200);
|
|
||||||
} else if (etype === 'table') {
|
|
||||||
var tblRows = el.rows || el.ROWS || [];
|
|
||||||
content = tblRows.length + '×' + (tblRows[0] ? tblRows[0].length : 0) + ' ячеек';
|
|
||||||
}
|
}
|
||||||
rows += '<tr><td>' + (idx+1) + '</td><td>' + etype + '</td><td>' + style + '</td><td style="max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + (content||'').replace(/</g,'<').replace(/>/g,'>') + '</td></tr>';
|
} else {
|
||||||
|
leftHtml = '<span style="color:var(--muted);">(ещё не загружен)</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Правая панель: распарсено (статистика + структура)
|
||||||
|
var rightHtml = '';
|
||||||
|
// Базовая инфа
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Размер</span><span class="v">' + formatSize(f.size) + '</span></div>';
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Изменён</span><span class="v">' + formatDate(f.lastModified) + '</span></div>';
|
||||||
|
if (f.parseInfo) {
|
||||||
|
var d = f.parseInfo;
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Элементов</span><span class="v">' + (d.ELEMENT_COUNT||0) + '</span></div>';
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Параграфов</span><span class="v">' + (d.PARAGRAPHS||0) + '</span></div>';
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Таблиц</span><span class="v">' + (d.TABLES||0) + '</span></div>';
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Строк таблиц</span><span class="v">' + (d.TABLE_ROWS||0) + '</span></div>';
|
||||||
|
if (d.PAGES) rightHtml += '<div class="kv"><span class="k">Страниц</span><span class="v">' + d.PAGES + '</span></div>';
|
||||||
|
if (d.PARSE_TIME_MS) {
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Время парсинга</span><span class="v">' + (d.PARSE_TIME_MS > 1000 ? (d.PARSE_TIME_MS/1000).toFixed(1) + ' с' : d.PARSE_TIME_MS + ' мс') + '</span></div>';
|
||||||
|
}
|
||||||
|
if (d.TEXT_LENGTH) rightHtml += '<div class="kv"><span class="k">Символов</span><span class="v">' + d.TEXT_LENGTH.toLocaleString() + '</span></div>';
|
||||||
|
|
||||||
|
// Заголовки таблиц
|
||||||
|
if (d.TABLE_HEADERS && d.TABLE_HEADERS.length > 0) {
|
||||||
|
rightHtml += '<div style="margin-top:10px;font-weight:600;font-size:12px;">Заголовки таблиц:</div>';
|
||||||
|
d.TABLE_HEADERS.forEach(function(hdr, ti) {
|
||||||
|
rightHtml += '<div style="margin-top:2px;font-size:10px;color:var(--muted);">Таблица ' + (ti+1) + ' (' + (hdr||[]).length + ' кол.):</div>';
|
||||||
|
rightHtml += '<pre>' + (hdr||[]).map(function(c){return c||'(пусто)';}).join(' | ') + '</pre>';
|
||||||
});
|
});
|
||||||
parsedHtml = '<div class="table-wrap"><table><thead><tr><th>№</th><th>Тип</th><th>Стиль</th><th>Содержание</th></tr></thead><tbody>' + rows + '</tbody></table></div>';
|
|
||||||
}
|
}
|
||||||
|
// Первые строки таблиц
|
||||||
|
if (d.TABLE_SAMPLES && d.TABLE_SAMPLES.length > 0) {
|
||||||
|
rightHtml += '<div style="margin-top:10px;font-weight:600;font-size:12px;">Первые строки:</div>';
|
||||||
|
d.TABLE_SAMPLES.forEach(function(sample, ti) {
|
||||||
|
rightHtml += '<div style="margin-top:2px;font-size:10px;color:var(--muted);">Таблица ' + (ti+1) + ':</div>';
|
||||||
|
rightHtml += '<pre>' + sample.map(function(row){ return (row||[]).map(function(c){return c||'(пусто)';}).join(' | '); }).join('\n') + '</pre>';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
// Ошибки
|
||||||
|
if (d.ERRORS && d.ERRORS.length > 0) {
|
||||||
|
rightHtml += '<div style="margin-top:8px;color:var(--destructive);font-weight:600;">Ошибки:</div>';
|
||||||
|
rightHtml += '<pre>' + d.ERRORS.join('\n') + '</pre>';
|
||||||
|
}
|
||||||
|
// Превью текста
|
||||||
|
if (d.TEXT_PREVIEW) {
|
||||||
|
rightHtml += '<div style="margin-top:10px;font-weight:600;font-size:12px;">Превью текста:</div>';
|
||||||
|
rightHtml += '<pre>' + d.TEXT_PREVIEW.substring(0, 5000).replace(/</g,'<').replace(/>/g,'>') + '</pre>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rightHtml += '<div style="color:var(--muted);margin-top:8px;">(ещё не распарсен)</div>';
|
||||||
|
}
|
||||||
|
rightHtml += '<div class="kv" style="margin-top:10px;"><span class="k">doc_id</span><span class="v">' + (f.doc_id || '—') + '</span></div>';
|
||||||
|
if (f.supp_id) {
|
||||||
|
rightHtml += '<div class="kv"><span class="k">supp_id</span><span class="v">' + f.supp_id + '</span></div>';
|
||||||
|
rightHtml += '<div class="kv"><span class="k">Тип ДС</span><span class="v">' + (f.supp_type || '—') + '</span></div>';
|
||||||
|
}
|
||||||
|
|
||||||
var html = '<div class="text-panes">' +
|
var html = '<div class="text-panes">' +
|
||||||
'<div class="text-pane"><div class="pane-title">Сырой текст</div><pre>' + rawText.replace(/</g,'<').replace(/>/g,'>') + '</pre></div>' +
|
'<div class="text-pane"><div class="pane-title">Сырой текст</div>' + leftHtml + '</div>' +
|
||||||
'<div class="text-pane"><div class="pane-title">Распарсено</div>' + parsedHtml + '</div>' +
|
'<div class="text-pane"><div class="pane-title">Распарсено</div>' + rightHtml + '</div>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
document.getElementById('modalBody').innerHTML = html;
|
document.getElementById('modalBody').innerHTML = html;
|
||||||
} catch(e) {
|
|
||||||
document.getElementById('modalBody').innerHTML = '<span style="color:var(--destructive);">Ошибка загрузки</span>';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// closeModal — сбросить wide при закрытии
|
|
||||||
var origCloseModal = closeModal;
|
|
||||||
closeModal = function(e) {
|
|
||||||
if (e && e.target !== document.getElementById('modalOverlay')) return;
|
|
||||||
document.querySelector('.modal').classList.remove('wide');
|
|
||||||
document.getElementById('modalOverlay').classList.remove('open');
|
|
||||||
};
|
|
||||||
|
|
||||||
window.showInfo = showInfo;
|
|
||||||
window.closeModal = closeModal;
|
window.closeModal = closeModal;
|
||||||
window.showView = showView;
|
|
||||||
window.showText = showText;
|
window.showText = showText;
|
||||||
|
|
||||||
// ── Промпт ───────────────────────────────────────────────────
|
// ── Промпт ───────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user