diff --git a/deploy/app.js b/deploy/app.js
index 095d321..c821573 100644
--- a/deploy/app.js
+++ b/deploy/app.js
@@ -336,15 +336,51 @@ window.runCompareForGroup = async function(gi) {
}, 200);
var es = new EventSource(VM_API + '/process-v2?contract_id=' + cid);
+ var sections = {};
es.onmessage = function(e) {
var d = JSON.parse(e.data);
- if (d.type === 'done') {
+
+ if (d.type === 'extract_start') {
+ var sec = document.createElement('div');
+ sec.style.cssText = 'margin-top:8px;border:1px solid var(--brand-gray);border-radius:6px;overflow:hidden;';
+ sec.innerHTML = '
';
+ 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') {
+ 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 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) + '
';
+ html += '| Действие | Услуга | Цена | Кол-во | Сумма | Дата |
';
+ d.ops.forEach(function(op) {
+ var cls = op.action === 'ADD' ? 'diff-added' : op.action === 'DELETE' ? 'diff-deleted' : 'diff-changed';
+ var nr = op.new_row || {};
+ html += '| ' + op.action + ' | ' + (nr.name||'') + ' | ' + (nr.price!=null?nr.price:'') + ' | ' + (nr.qty!=null?nr.qty:'') + ' | ' + (nr.sum!=null?nr.sum:'') + ' | ' + (nr.date_start||'') + ' |
';
+ });
+ html += '
';
+ body.innerHTML = html;
+ body.style.display = 'block';
+ }
+ }
+ else if (d.type === 'done') {
clearInterval(timer); es.close();
diffStatus.textContent = '✓ ' + d.total_time_s + 'с';
btn.innerHTML = '✓ Готово'; btn.disabled = false;
- } else if (d.type === 'applied') {
- diffBody.innerHTML += '+' + (d.summary.added||0) + ' ~' + (d.summary.updated||0) + ' -' + (d.summary.deleted||0) + '
';
- } else if (d.type === 'error') {
+ }
+ else if (d.type === 'error') {
clearInterval(timer); es.close();
diffBody.innerHTML += '✗ ' + d.message + '
';
btn.innerHTML = '✗'; btn.disabled = false;