From bec16def95021df0a61ad656c4eae6085fdb2c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Fri, 19 Jun 2026 13:50:17 +0400 Subject: [PATCH] =?UTF-8?q?v2.0.10:=20=D0=BF=D1=80=D1=8F=D0=BC=D0=B0=D1=8F?= =?UTF-8?q?=20FormData=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D1=87=D0=B0=D0=BD?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/templates/upload.html | 97 ++++++++++---------------------------- 1 file changed, 24 insertions(+), 73 deletions(-) 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 @@
Nubes - Сверка договоров 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;