diff --git a/site/templates/upload.html b/site/templates/upload.html
index 53161cb..24d3f7a 100644
--- a/site/templates/upload.html
+++ b/site/templates/upload.html
@@ -60,7 +60,7 @@
 }})
-
Сверка договоров v2.0.9
+
Сверка договоров v2.0.10
@@ -156,81 +156,35 @@
window.removeFile = removeFile;
- // ── Чанковая загрузка v2 (30KB + MD5) ────────────────────
+ // ── Прямая загрузка FormData ─────────────────────────────
- function uploadFileChunked(file, cid, onProgress) {
+ function uploadFile(file, onProgress) {
return new Promise(function(resolve, reject) {
- var reader = new FileReader();
- reader.onload = function() {
- var buffer = reader.result;
- var bytes = new Uint8Array(buffer);
- // Чанковая конвертация в base64 — apply не тянет >125K аргументов
- var b64Chunks = [];
- var B64_CHUNK = 0x8000; // 32768 bytes
- for (var bi = 0; bi < bytes.length; bi += B64_CHUNK) {
- b64Chunks.push(String.fromCharCode.apply(null, bytes.subarray(bi, bi + B64_CHUNK)));
- }
- var b64 = btoa(b64Chunks.join(''));
- var checksum = SparkMD5.ArrayBuffer.hash(buffer);
- var CHUNK = 60 * 1024; // ближе к лимиту 64KB → меньше чанков
- var totalChunks = Math.ceil(b64.length / CHUNK);
- var uploadId = 'u' + Date.now().toString(36) + Math.random().toString(36).substr(2, 7);
- var done = 0;
+ var fd = new FormData();
+ fd.append('files', file);
+ if (contractId) fd.append('cid', contractId);
- console.log('uploadFileChunked: ' + file.name + ' b64=' + b64.length + ' chunks=' + totalChunks + ' uploadId=' + uploadId);
-
- function fetchWithRetry(url, body, retries) {
- retries = retries || 3;
- return fetch(url, {
- method: 'POST',
- headers: {'Content-Type': 'application/json'},
- body: JSON.stringify(body)
- }).catch(function(e) {
- if (retries > 0) {
- console.log('retry ' + url + ' (' + retries + ' left): ' + e.message);
- return new Promise(function(r) { setTimeout(r, 1000); }).then(function() {
- return fetchWithRetry(url, body, retries - 1);
- });
- }
- throw e;
- });
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST', '/');
+ xhr.upload.onprogress = function(e) {
+ if (e.lengthComputable && onProgress) {
+ onProgress(Math.round(e.loaded / e.total * 100));
}
-
- function sendChunk(i) {
- if (i >= totalChunks) {
- console.log('finalize: ' + uploadId);
- fetchWithRetry('/v2/finalize', {upload_id: uploadId, filename: file.name, total: totalChunks, checksum: checksum})
- .then(function(r) {
- if (!r.ok) throw new Error('HTTP ' + r.status);
- return r.json();
- }).then(function(data) {
- if (data.ok) resolve({contract_id: data.contract_id});
- else reject(new Error(data.error));
- }).catch(function(e) { reject(e); });
- return;
- }
- var piece = b64.substring(i * CHUNK, (i + 1) * CHUNK);
- console.log('chunk ' + i + '/' + totalChunks + ' send ' + piece.length + ' bytes');
- fetchWithRetry('/v2/chunk', {upload_id: uploadId, index: i, total: totalChunks, data: piece})
- .then(function(r) {
- if (!r.ok) throw new Error('HTTP ' + r.status);
- return r.json();
- }).then(function(data) {
- if (!data.ok) { reject(new Error(data.error)); return; }
- done++;
- if (onProgress) onProgress({pct: Math.round(done / totalChunks * 100), done: done, total: totalChunks});
- setTimeout(function() { sendChunk(i + 1); }, 3000);
- }).catch(function(e) { reject(e); });
- }
- sendChunk(0);
};
- reader.onerror = function() { reject(new Error('Read error')); };
- reader.readAsArrayBuffer(file);
+ xhr.onload = function() {
+ try {
+ var r = JSON.parse(xhr.responseText);
+ if (r.contract_id) resolve(r);
+ else reject(new Error(r.error || 'Неизвестная ошибка'));
+ } catch(e) { reject(new Error('Некорректный ответ')); }
+ };
+ xhr.onerror = function() { reject(new Error('Сеть')); };
+ xhr.ontimeout = function() { reject(new Error('Таймаут')); };
+ xhr.timeout = 120000;
+ xhr.send(fd);
});
}
- // ── Старая загрузка (одним POST) ─────────────────────────────
-
// ── Выбор файла → сразу загрузка ────────────────────────────
fileInput.addEventListener('change', async function() {
@@ -252,16 +206,13 @@
var startTime = Date.now();
try {
- var resp = await uploadFileChunked(f, contractId, function(info) {
- fileQueue[rowIdx].status = '↑ чанк ' + info.done + '/' + info.total + ' (' + info.pct + '%)';
+ var resp = await uploadFile(f, function(pct) {
+ fileQueue[rowIdx].status = '↑ ' + pct + '%';
renderTable();
});
- // uploadFileChunked10k: прогресс по чанкам
- // но этот же resp приходит только с последнего чанка
if (resp && resp.contract_id) {
contractId = resp.contract_id;
}
- // Если файл был один и он маленький (один чанк), contract_id уже есть
var elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
fileQueue[rowIdx].status = '✓ ' + elapsed + 'с';
fileQueue[rowIdx].uploaded = true;