Implement reusable upload platform

This commit is contained in:
“Naeel”
2026-09-05 08:51:32 +03:00
parent 82d9ca9136
commit c0b87880ae
35 changed files with 734 additions and 9 deletions
+77 -4
View File
@@ -3,13 +3,86 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Upload Platform</title>
<title>Upload Platform {{ version }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<main>
<h1>Upload Platform</h1>
<p>Version: {{ version }}</p>
<main class="page">
<header>
<p class="eyebrow">FILE INTAKE / {{ version }}</p>
<h1>Загрузка документов</h1>
<p class="lede">Выберите отдельные файлы или целую папку. Архивы будут раскрыты автоматически.</p>
</header>
<section class="toolbar" aria-label="Выбор файлов">
<input id="file-input" type="file" multiple hidden>
<input id="folder-input" type="file" webkitdirectory directory multiple hidden>
<button id="files-btn" type="button">Выбрать файлы</button>
<button id="folder-btn" type="button" class="secondary">Выбрать папку</button>
<button id="upload-btn" type="button" disabled>Загрузить</button>
<button id="clear-btn" type="button" class="quiet">Очистить</button>
</section>
<p id="status" class="status" role="status"></p>
<div class="table-wrap">
<table>
<thead><tr><th>Путь</th><th>Размер</th><th>Статус</th></tr></thead>
<tbody id="table-body"></tbody>
</table>
</div>
<p id="count" class="count"></p>
<section id="result" class="result" hidden>
<h2>Файлы в сессии</h2>
<ul id="result-list"></ul>
</section>
</main>
<script src="{{ url_for('static', filename='vendor/fflate.min.js') }}"></script>
<script type="module">
import { initUploadTable } from "/upload-frontend/table/init_upload_table.js";
import { uploadViaVM } from "/upload-frontend/upload/upload_via_vm.js";
const cfg = {{ config|tojson }};
const table = initUploadTable({
...cfg,
fileInputEl: document.querySelector('#file-input'),
folderInputEl: document.querySelector('#folder-input'),
tableBodyEl: document.querySelector('#table-body'),
countEl: document.querySelector('#count'),
uploadBtnEl: document.querySelector('#upload-btn'),
});
const status = document.querySelector('#status');
document.querySelector('#files-btn').onclick = () => table.pickFiles();
document.querySelector('#folder-btn').onclick = () => table.pickFolder();
document.querySelector('#clear-btn').onclick = () => table.clear();
document.querySelector('#upload-btn').onclick = async () => {
const files = table.getFiles().map((item) => item.file);
table.setBusy(true);
status.textContent = 'Загрузка...';
const result = await uploadViaVM(files, cfg.vmUploadUrl, {
onUploadStatus: (text) => { status.textContent = text; },
onStatus: (name, text) => {
const item = table.getFiles().find((entry) => entry.name === name);
if (item) table.setStatus(item.path, text);
},
});
if (!result.ok) {
status.textContent = result.error;
table.setBusy(false);
return;
}
const response = await fetch('/api/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session: result.session }),
});
const processed = await response.json();
status.textContent = `Готово: ${processed.files.length} файлов`;
document.querySelector('#result').hidden = false;
const resultList = document.querySelector('#result-list');
resultList.replaceChildren(...processed.files.map((file) => {
const item = document.createElement('li');
item.textContent = `${file.name}${file.size} B`;
return item;
}));
};
</script>
</body>
</html>