Integrate Obfuscator file picker into Contracts
Deploy contracts-flask / validate (push) Canceled after 0s
Deploy contracts-flask / validate (push) Canceled after 0s
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+25
-42
@@ -1,45 +1,51 @@
|
||||
// ⛔ НЕ МЕНЯТЬ БЕЗ РАЗРЕШЕНИЯ НАЕЛЯ ⛔
|
||||
// Contracts App v2.0 — всё на Flask, ВМ больше нет
|
||||
// Contracts App v2.0 — backend на Flask; ВМ используется только как upload buffer.
|
||||
var VM_API = '';
|
||||
// ВМ-буфер загрузки (паттерн drhider): браузер кладёт файл сюда (WebDAV, мимо шлюза),
|
||||
// бэк сам тянет его по /api/upload_refs. Origin должен быть в CORS на nginx ВМ.
|
||||
var VM_UPLOAD_URL = 'https://contracts.kube5s.ru/contracts-upload/';
|
||||
// SITE_URL удалён (Фаза 4) — не использовался
|
||||
|
||||
var fileInput = document.getElementById('fileInput');
|
||||
var fileTable = document.getElementById('fileTable');
|
||||
// state.files — теперь в state.js (Фаза 0: state + render)
|
||||
// state.contractId — теперь в state.js (Фаза 0: state + render)
|
||||
// state.batchId — теперь в state.js (Фаза 0: state + render)
|
||||
// (batchId = crypto.randomUUID() — уникальный ID сессии для классификации)
|
||||
|
||||
// Прогрев upstream + автоочистка при загрузке страницы
|
||||
// Прогрев приложения при загрузке страницы.
|
||||
// ⚠️ Без прогрева первый POST может упасть с ERR_CONNECTION_RESET (MTU/Geneve)
|
||||
(async function init() {
|
||||
try { await fetch('/health'); } catch(e) { /* ignore */ }
|
||||
try { await fetch(VM_API + '/api/cleanup', { method: 'POST' }); } catch(e) { /* ignore */ }
|
||||
})();
|
||||
|
||||
/**
|
||||
* render(state) — Главная функция рендеринга (Фаза 0, decoupling-final-plan.md).
|
||||
*
|
||||
* ПАТТЕРН: action → мутация state → render(state)
|
||||
*
|
||||
* Фаза 0: вызывает существующий renderTable().
|
||||
* renderTable читает state.files напрямую (state — глобальный объект).
|
||||
* Фаза 1+: будет вызывать renderFiles(state), renderGroups(state), renderStepper(state) и т.д.
|
||||
*
|
||||
* ПРАВИЛО: любое изменение state ДОЛЖНО завершаться вызовом render(state).
|
||||
* Никакой прямой манипуляции DOM в обход render().
|
||||
* console.log(state) показывает ВСЁ состояние в любой момент.
|
||||
* Обновить отображение picker и текущий шаг pipeline после изменения state.
|
||||
*/
|
||||
function render(state) {
|
||||
renderFiles(state);
|
||||
renderStepper(state);
|
||||
}
|
||||
|
||||
// syncDB, statusToHTML, renderFiles, toggleClassifyDetail, uploadFile, refreshSupps
|
||||
// → вынесены в files.js (Фаза 1)
|
||||
if (!window.FilePicker) throw new Error('Не загружен бандл FilePicker');
|
||||
filePicker = window.FilePicker.initFilePicker({
|
||||
mount: '#filePicker',
|
||||
allowedExt: ['.pdf', '.doc', '.docx'],
|
||||
limits: FILE_PICKER_LIMITS,
|
||||
onChange: onPickerFilesChange,
|
||||
onError: function(error, file) {
|
||||
filePicker.setMessage('Ошибка чтения ' + file.name + ': ' + error.message);
|
||||
},
|
||||
onDetails: function(id) {
|
||||
var index = state.files.findIndex(function(file) { return file.pickerId === id; });
|
||||
if (index >= 0) toggleClassifyDetail(index);
|
||||
},
|
||||
onText: function(id) {
|
||||
var index = state.files.findIndex(function(file) { return file.pickerId === id; });
|
||||
if (index >= 0) showText(index);
|
||||
}
|
||||
});
|
||||
|
||||
// Picker selection, upload queue, syncDB, document details and finalization
|
||||
// are wired by files.js.
|
||||
|
||||
// ── Pipeline stepper (Фаза 4: state-driven) ──────────────────
|
||||
|
||||
@@ -97,36 +103,13 @@ function resetStepper(fromId) {
|
||||
}
|
||||
// Утилиты (formatSize, formatDate, moveUp, moveDown, escHtml, fmtDate) —
|
||||
// вынесены в app_utils.js для облегчения анализа и отладки.
|
||||
// statusToHTML, renderFiles → files.js (Фаза 1)
|
||||
// Picker rows are rendered by the FilePicker integration in files.js.
|
||||
|
||||
// ── Раскрыть/скрыть результат классификации под строкой файла ──
|
||||
// toggleClassifyDetail → files.js (Фаза 1)
|
||||
|
||||
// moveUp/moveDown/removeFile/openAbout/closeAbout — вынесены в app_utils.js
|
||||
|
||||
// ── Автозагрузка при выборе файлов ──────────────────────────
|
||||
// Фаза 1 (decoupling-final-plan.md): fileInput handler разбит на чистые функции
|
||||
// onFilesSelected → reconcileSelection → addZipFile/addRegularFile → finalizeUpload
|
||||
// Вся логика — в files.js. Здесь только тонкая обёртка.
|
||||
fileInput.addEventListener('change', async function() {
|
||||
var newFiles = Array.from(fileInput.files);
|
||||
onFilesSelected(newFiles);
|
||||
});
|
||||
|
||||
// Выбор папки (webkitdirectory) — та же обработка, что и файлы
|
||||
var folderInput = document.getElementById('folderInput');
|
||||
var folderBtn = document.getElementById('folderBtn');
|
||||
if (folderBtn && folderInput) {
|
||||
folderBtn.addEventListener('click', function() { folderInput.click(); });
|
||||
folderInput.addEventListener('change', function() {
|
||||
var files = Array.from(folderInput.files).filter(function(f) {
|
||||
var n = f.name.toLowerCase();
|
||||
return n.endsWith('.pdf') || n.endsWith('.doc') || n.endsWith('.docx') || n.endsWith('.zip');
|
||||
});
|
||||
if (files.length) onFilesSelected(files);
|
||||
});
|
||||
}
|
||||
|
||||
// ── Классификация ──────────────────────────────────────────
|
||||
function showClassifyBtn() {
|
||||
var btn = document.getElementById('classifyBtn');
|
||||
|
||||
Reference in New Issue
Block a user