diff --git a/deploy/convert_server.py b/deploy/convert_server.py index 9f092cb..04fabf4 100755 --- a/deploy/convert_server.py +++ b/deploy/convert_server.py @@ -208,7 +208,7 @@ class Handler(BaseHTTPRequestHandler): ar = apply_resp.json() # Lucee serializeJSON → UPPERCASE keys summary = {k.lower(): v for k, v in ar.get("SUMMARY", {}).items()} - self._sse({"type": "applied", "supplement_id": sid, "summary": summary}) + self._sse({"type": "applied", "supplement_id": sid, "summary": summary, "ops": ops}) else: self._sse({"type": "apply_error", "supplement_id": sid, "error": f"apply HTTP {apply_resp.status_code}"}) diff --git a/index.cfm b/index.cfm index 57426ab..45675c5 100644 --- a/index.cfm +++ b/index.cfm @@ -71,7 +71,7 @@
Nubes - Сверка договоров — LLM v1.0.90 — Lucee + Сверка договоров — LLM v1.0.91 — Lucee
@@ -338,19 +338,51 @@ document.getElementById('llmBtn').addEventListener('click', function() { }, 200); var es = new EventSource('https://contracts.kube5s.ru/process-v2?contract_id=' + contractId); + var sections = {}; // supplement_id → DOM element es.onmessage = function(e) { var d = JSON.parse(e.data); if (d.type === 'extract_start') { - diffBody.innerHTML += '
⏳ ' + d.filename + ' → LLM...
'; + var sec = document.createElement('div'); + sec.style.cssText = 'margin-top:8px;border:1px solid var(--brand-gray);border-radius:6px;overflow:hidden;'; + sec.innerHTML = '
⏳ ' + d.filename + '
'; + sec.querySelector('.diff-section-header').addEventListener('click', function() { + var body = sec.querySelector('.diff-section-body'); + body.style.display = body.style.display === 'none' ? 'block' : 'none'; + }); + diffBody.appendChild(sec); + sections[d.supplement_id] = sec; } else if (d.type === 'llm_done') { - diffBody.innerHTML += '
✓ ' + d.filename + ': ' + d.ops_count + ' операций, ' + d.mode + ' (' + d.time_s + 'с)
'; + var sec = sections[d.supplement_id]; + if (sec) { + sec.querySelector('.diff-section-header').innerHTML = '✓ ' + d.filename + ' — ' + d.ops_count + ' оп., ' + d.mode + ' (' + d.time_s + 'с)'; + sec.querySelector('.diff-section-header').style.color = 'var(--green)'; + } } else if (d.type === 'applied') { - var s = d.summary || {}; - diffBody.innerHTML += '
+' + (s.added||0) + ' ~' + (s.updated||0) + ' -' + (s.deleted||0) + ' ?' + (s.unresolved||0) + '
'; + var sec = sections[d.supplement_id]; + if (sec && d.ops && d.ops.length > 0) { + var s = d.summary || {}; + var body = sec.querySelector('.diff-section-body'); + var html = '
+' + (s.added||0) + ' ~' + (s.updated||0) + ' -' + (s.deleted||0) + ' ?' + (s.unresolved||0) + '
'; + html += '
'; + d.ops.forEach(function(op) { + var action = op.action; + var cls = action === 'ADD' ? 'diff-added' : action === 'DELETE' ? 'diff-deleted' : action === 'UPDATE' ? 'diff-changed' : ''; + var nr = op.new_row || {}; + var name = nr.name || ''; + var price = nr.price != null ? nr.price : ''; + var qty = nr.qty != null ? nr.qty : ''; + var sum = nr.sum != null ? nr.sum : ''; + var ds = nr.date_start || ''; + html += ''; + }); + html += '
ДействиеУслугаЦенаКол-воСуммаДата
' + action + '' + name + '' + price + '' + qty + '' + sum + '' + ds + '
'; + body.innerHTML = html; + body.style.display = 'block'; + } } else if (d.type === 'extract_error' || d.type === 'apply_error') { diffBody.innerHTML += '
✗ ' + d.filename + ': ' + d.error + '
'; @@ -381,7 +413,7 @@ document.getElementById('llmBtn').addEventListener('click', function() { if (diffBody.innerHTML === '') { diffBody.innerHTML = '
✗ Ошибка соединения
'; } - btn.innerHTML = ' Сравнить v2'; + btn.innerHTML = ' Сравнить'; btn.disabled = false; lucide.createIcons(); };