From 51b9cffd0f795e85d0343b75c7870b754eae9559 Mon Sep 17 00:00:00 2001 From: WASRUSGEN Date: Sat, 30 May 2026 16:52:55 +0300 Subject: [PATCH] feat: S3 file upload UI with storage bar, per-tier limits --- mockup.html | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 164 insertions(+), 4 deletions(-) diff --git a/mockup.html b/mockup.html index 13f487d..9417f21 100644 --- a/mockup.html +++ b/mockup.html @@ -2369,11 +2369,37 @@ body{font-family:var(--font-ui);background:var(--surf);color:var(--ink);line-hei - +
-
Кабинет

Мои документы

-
-
Аудит документов по Вашей ситуации. Отмечайте что есть — покажу что грозит если чего-то не хватает 💛
+
Кабинет
+
+

Мои документы

+
+ +
+
+ + + + + +
+ +
+ +
+
Аудит документов по Вашей ситуации. Загрузите фото/скан договора или отмечайте что есть — покажу риски.
@@ -8035,6 +8061,7 @@ function tab(name){ if(name==='casemap' && typeof renderCaseMap==='function') renderCaseMap(); if(name==='team' && typeof renderTeamDashboard==='function') renderTeamDashboard(); if(name==='docs') { + if(typeof _renderUploadedDocs==='function') _renderUploadedDocs(); var contracts = typeof _getContracts === 'function' ? _getContracts() : []; if (contracts.length && typeof renderDocChecklist === 'function') renderDocChecklist(contracts[0].type); else if (typeof renderDocChecklist === 'function') renderDocChecklist(''); @@ -9633,6 +9660,139 @@ function _toggleDocCheck(key, docId, checked) { } catch(e){} } +// ── ФАЙЛОВОЕ ХРАНИЛИЩЕ (S3) ────────────────────────────────────────────────── + +var _uploadedFiles = []; // локальный кэш загруженных файлов + +function _uploadFiles(input) { + var files = Array.from(input.files || []); + if (!files.length) return; + + var user = _getOrgUser(); + var caseId = 'general'; + + // Показываем прогресс + var upArea = document.getElementById('docs-uploaded'); + if (!upArea) return; + + files.forEach(function(file) { + var itemId = 'up_' + Date.now() + '_' + Math.random().toString(36).slice(2,6); + var item = document.createElement('div'); + item.id = itemId; + item.style.cssText = 'display:flex;align-items:center;gap:10px;padding:10px;border:1.5px solid var(--line);border-radius:10px;margin-bottom:8px;background:#fafafa'; + item.innerHTML = + '
' + + (file.type.includes('image') ? '🖼' : file.type.includes('pdf') ? '📄' : '📎') + + '
' + + '
' + + '
' + file.name + '
' + + '
Загружаю... ' + (file.size/1024).toFixed(0) + ' KB
' + + '
'; + upArea.insertBefore(item, upArea.firstChild); + + var form = new FormData(); + form.append('file', file); + form.append('case_id', caseId); + form.append('doc_type', 'document'); + if (user && user.token) form.append('token', user.token); + + fetch(API_BASE + '/api/files/upload', { method: 'POST', body: form }) + .then(function(r){ return r.json(); }) + .then(function(d) { + var st = document.getElementById(itemId + '_status'); + if (d.error) { + if (st) st.innerHTML = '❌ ' + d.error + ''; + return; + } + if (st) st.innerHTML = '✅ Загружен · ' + d.size_mb + ' MB'; + _uploadedFiles.push({ id: d.file_id, name: file.name, size_mb: d.size_mb, url: d.url, type: file.type }); + _updateStorageBar(); + // Если это изображение — предлагаем отправить на анализ + if (file.type.includes('image')) { + var btn = document.createElement('button'); + btn.className = 'svc-btn-detail'; + btn.style.cssText = 'font-size:11px;white-space:nowrap'; + btn.textContent = '🔍 Анализировать'; + btn.onclick = function(){ _analyzeUploadedImage(d.url, file.name); }; + item.appendChild(btn); + } + }) + .catch(function(e){ + var st = document.getElementById(itemId + '_status'); + if (st) { + // S3 не настроен — сохраняем локально + st.innerHTML = '📱 Сохранён локально (S3 не настроен)'; + _uploadedFiles.push({ id: itemId, name: file.name, type: file.type, local: true }); + } + }); + }); + + // Сбрасываем input + input.value = ''; +} + +function _updateStorageBar() { + var user = _getOrgUser(); + if (!user) return; + fetch(API_BASE + '/api/files/storage_info', { + method: 'POST', headers: {'Content-Type':'application/json'}, + body: JSON.stringify({ token: user.token, plan: 'start' }) + }) + .then(function(r){ return r.json(); }) + .then(function(d) { + var bar = document.getElementById('storage-bar'); + if (bar) bar.style.display = ''; + var usedEl = document.getElementById('storage-used-label'); + var limEl = document.getElementById('storage-limit-label'); + var fillEl = document.getElementById('storage-fill'); + if (usedEl) usedEl.textContent = d.used_mb + ' MB использовано'; + if (limEl) limEl.textContent = d.limit_gb === -1 ? 'без лимита' : 'из ' + d.limit_gb + ' GB'; + if (fillEl) fillEl.style.width = (d.percent || 0) + '%'; + if (d.percent > 80) fillEl.style.background = '#d97706'; + if (d.percent > 95) fillEl.style.background = '#dc2626'; + }) + .catch(function(){}); +} + +function _analyzeUploadedImage(url, filename) { + // Открываем диалог Елены с предложением проанализировать + toast('📋 Передаю в Елену для анализа...'); + var wrap = document.querySelector('.chatwrap'); + if (!wrap) return; + var div = document.createElement('div'); + div.className = 'hc-msg hc-elena'; + div.innerHTML = '' + + '
Вижу загруженный файл ' + filename + '. ' + + 'Для анализа вставьте текст договора в поле ниже — Елена разберёт риски и сроки.
'; + wrap.appendChild(div); + wrap.scrollTop = wrap.scrollHeight; +} + +// Загружаем список файлов при открытии вкладки +function _renderUploadedDocs() { + var user = _getOrgUser(); + if (!user) return; + fetch(API_BASE + '/api/files/list', { + method: 'POST', headers: {'Content-Type':'application/json'}, + body: JSON.stringify({ token: user.token, case_id: 'general' }) + }) + .then(function(r){ return r.json(); }) + .then(function(d) { + var el = document.getElementById('docs-uploaded'); if (!el) return; + if (!d.files || !d.files.length) return; + el.innerHTML = d.files.map(function(f){ + var ico = (f.mime_type||'').includes('image') ? '🖼' : (f.mime_type||'').includes('pdf') ? '📄' : '📎'; + var kb = Math.round((f.size_bytes||0) / 1024); + return '
' + + '
' + ico + '
' + + '
' + f.original_name + '
' + + '
' + f.doc_type + ' · ' + kb + ' KB · ' + (f.created_at||'').slice(0,10) + '
' + + '
'; + }).join(''); + _updateStorageBar(); + }).catch(function(){}); +} + // ── БИБЛИОТЕКА ПОДПИСЕЙ И ПЕЧАТЕЙ ──────────────────────────────────────────── var _SIG_LIB_KEY = 'zashita_sig_library';