';
- return rows;
- }).join('');
- }
- lucide.createIcons();
-}
+// statusToHTML, renderFiles → files.js (Фаза 1)
// ── Раскрыть/скрыть результат классификации под строкой файла ──
-window.toggleClassifyDetail = async function(i) {
- var detailRow = document.getElementById('detail_' + i);
- var expandIcon = document.getElementById('expand_' + i);
- if (!detailRow) return;
-
- if (detailRow.style.display !== 'none') {
- detailRow.style.display = 'none';
- if (expandIcon) expandIcon.textContent = '▸';
- return;
- }
-
- var f = state.files[i];
- if (!f || !f.doc_id) return;
-
- detailRow.style.display = '';
- if (expandIcon) expandIcon.textContent = '▾';
-
- try {
- var resp = await fetch(VM_API + '/api/documents/' + f.doc_id);
- var qData = await resp.json();
- if (!qData.ok) { detailRow.cells[0].innerHTML = 'Ошибка загрузки'; return; }
-
- var html = '';
- if (qData.classify_status === 'classified') {
- html += '
🏷️ Результат классификации
';
- html += '
';
- if (qData.doc_type) html += 'Тип: ' + escHtml(qData.doc_type) + '';
- if (qData.own_number) html += 'Номер: ' + escHtml(qData.own_number) + '';
- if (qData.parent_number) html += 'Родительский: ' + escHtml(qData.parent_number) + '';
- if (qData.doc_date) html += 'Дата: ' + escHtml(qData.doc_date) + '';
- if (qData.counterparty) html += 'Контрагент: ' + escHtml(qData.counterparty) + '';
- html += '
';
- if (qData.classify_input) {
- html += '📤 Текст отправленный в LLM';
- html += '
' + escHtml(qData.classify_input) + '
';
- html += '';
- }
- if (qData.classify_raw) {
- html += '📥 Сырой ответ LLM';
- html += '
' + escHtml(qData.classify_raw) + '
';
- html += '';
- }
- if (qData.elements_json) {
- var ej = qData.elements_json;
- if (typeof ej === 'object' && ej.Value) ej = ej.Value;
- var ejStr = typeof ej === 'string' ? ej : JSON.stringify(ej, null, 2);
- html += '📄 Распарсенные элементы (JSON)';
- html += '
';
+ return rows;
+ }).join('');
+ }
+ lucide.createIcons();
+}
+
+/**
+ * syncDB() — Синхронизация БД с текущим состоянием файлов.
+ *
+ * Отправляет на бэкенд список doc_id, которые должны остаться в БД.
+ * Всё, чего нет в state.files, будет удалено из БД (cascade).
+ * Вызывается после каждого изменения состава файлов (removeFile, upload).
+ */
+async function syncDB() {
+ var keepIds = state.files.map(function(f) { return f.doc_id; }).filter(Boolean);
+ try {
+ await fetch(VM_API + '/api/sync', {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({keep_ids: keepIds})
+ });
+ } catch(e) { /* сервер недоступен — не критично */ }
+}
+
+/**
+ * toggleClassifyDetail(i) — Раскрыть/скрыть результат классификации под строкой файла.
+ *
+ * Вызывается по клику на имя файла в таблице.
+ * Загружает данные с бэкенда (/api/documents/:id) и показывает:
+ * - Тип, номер, родительский номер, дату, контрагента
+ * - Текст отправленный в LLM (📤)
+ * - Сырой ответ LLM (📥)
+ * - Распарсенные элементы JSON (📄)
+ */
+window.toggleClassifyDetail = async function(i) {
+ var detailRow = document.getElementById('detail_' + i);
+ var expandIcon = document.getElementById('expand_' + i);
+ if (!detailRow) return;
+
+ if (detailRow.style.display !== 'none') {
+ detailRow.style.display = 'none';
+ if (expandIcon) expandIcon.textContent = '▸';
+ return;
+ }
+
+ var f = state.files[i];
+ if (!f || !f.doc_id) return;
+
+ detailRow.style.display = '';
+ if (expandIcon) expandIcon.textContent = '▾';
+
+ try {
+ var resp = await fetch(VM_API + '/api/documents/' + f.doc_id);
+ var qData = await resp.json();
+ if (!qData.ok) { detailRow.cells[0].innerHTML = 'Ошибка загрузки'; return; }
+
+ var html = '';
+ if (qData.classify_status === 'classified') {
+ html += '
🏷️ Результат классификации
';
+ html += '
';
+ if (qData.doc_type) html += 'Тип: ' + escHtml(qData.doc_type) + '';
+ if (qData.own_number) html += 'Номер: ' + escHtml(qData.own_number) + '';
+ if (qData.parent_number) html += 'Родительский: ' + escHtml(qData.parent_number) + '';
+ if (qData.doc_date) html += 'Дата: ' + escHtml(qData.doc_date) + '';
+ if (qData.counterparty) html += 'Контрагент: ' + escHtml(qData.counterparty) + '';
+ html += '
';
+ if (qData.classify_input) {
+ html += '📤 Текст отправленный в LLM';
+ html += '
' + escHtml(qData.classify_input) + '
';
+ html += '';
+ }
+ if (qData.classify_raw) {
+ html += '📥 Сырой ответ LLM';
+ html += '
' + escHtml(qData.classify_raw) + '
';
+ html += '';
+ }
+ if (qData.elements_json) {
+ var ej = qData.elements_json;
+ if (typeof ej === 'object' && ej.Value) ej = ej.Value;
+ var ejStr = typeof ej === 'string' ? ej : JSON.stringify(ej, null, 2);
+ html += '📄 Распарсенные элементы (JSON)';
+ html += '