process.cfm: один запрос вместо N+1, skip already extracted, DELETE before INSERT, prompt fix (v1.0.49)

This commit is contained in:
2026-06-19 08:48:29 +04:00
parent 93a4aa9eb8
commit d6ca31251b
3 changed files with 334 additions and 41 deletions
+44 -40
View File
@@ -61,7 +61,7 @@
<body>
<div class="topbar">
<img src="/nubes-logo.svg" alt="Nubes">
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.47 — Lucee</span></span>
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.49 — Lucee</span></span>
</div>
<div class="content">
@@ -340,54 +340,58 @@ document.getElementById('llmBtn').addEventListener('click', async function() {
diffStatus.textContent = '⏳ ' + ((Date.now() - llmStart) / 1000).toFixed(1) + 'с';
}, 200);
// 1. Extract for each supplement
// ОДИН запрос — всё внутри: экстракция + сравнение
try {
var resp = await fetch('/api.cfm?action=query&sql=' + encodeURIComponent("SELECT id FROM supplements WHERE contract_id='" + contractId + "' ORDER BY created_at"));
var resp = await fetch('/process.cfm?contract_id=' + contractId);
var data = await resp.json();
if (data.OK && data.ROWS) {
for (var i = 0; i < data.ROWS.length; i++) {
try {
var er = await fetch('/extractor.cfm?supplement_id=' + data.ROWS[i].id);
var ed = await er.json();
if (ed.OK) diffBody.innerHTML += '<div style="font-size:12px;color:var(--green);">✓ ' + ed.ROWS_SAVED + ' строк</div>';
else diffBody.innerHTML += '<div style="font-size:12px;color:var(--destructive);">✗ ' + (ed.ERROR||'') + '</div>';
} catch(e) {}
}
}
} catch(e) {}
// 2. Differ
diffBody.innerHTML += '<div style="margin-top:8px;font-weight:600;">📊 Сравнение:</div>';
try {
var resp = await fetch('/differ.cfm?contract_id=' + contractId);
var data = await resp.json();
if (data.OK && data.ALL_CHANGES) {
var all = data.ALL_CHANGES;
if (data.OK) {
// Показать результаты экстракции
var extr = data.EXTRACTED || [];
diffBody.innerHTML = '';
all.forEach(function(ch) {
var s = ch.SUMMARY || {};
diffBody.innerHTML += '<div style="font-weight:600;margin-top:12px;">📄 Допник (' + ch.TYPE + ')</div>';
diffBody.innerHTML += '<div style="font-size:12px;margin-left:8px;"><span style="color:var(--green);">+' + (s.ADDED||0) + '</span> <span style="color:#eab308;">~' + (s.CHANGED||0) + '</span> <span style="color:var(--destructive);">-' + (s.DELETED||0) + '</span></div>';
diffStatus.textContent = 'изм:' + (s.CHANGED||0) + ' +' + (s.ADDED||0) + ' -' + (s.DELETED||0);
var changes = ch.CHANGES || [];
if (changes.length === 0) {
diffBody.innerHTML += '<div style="color:var(--muted);font-size:12px;">Нет изменений</div>';
extr.forEach(function(e) {
if (e.ERROR) {
diffBody.innerHTML += '<div style="font-size:12px;color:var(--destructive);">✗ ' + (e.FILENAME||e.SUPPLEMENT_ID) + ': ' + e.ERROR + '</div>';
} else if (e.SKIPPED) {
diffBody.innerHTML += '<div style="font-size:12px;color:var(--muted);">⏭ ' + (e.FILENAME||e.SUPPLEMENT_ID) + ' (уже извлечено, ' + e.ROWS_SAVED + ' строк)</div>';
} else {
var tbl = '<div class="table-wrap" style="margin-top:4px;"><table><thead><tr><th>№</th><th>Услуга</th><th>Цена</th><th>Объём</th><th>Сумма</th><th>Начало</th></tr></thead><tbody>';
changes.forEach(function(c) {
var cls = c.CHANGE_TYPE === 'added' ? 'diff-added' : c.CHANGE_TYPE === 'deleted' ? 'diff-deleted' : c.CHANGE_TYPE === 'changed' ? 'diff-changed' : '';
var vals = c.NEW_VALUES && Object.keys(c.NEW_VALUES).length > 0 ? c.NEW_VALUES : (c.OLD_VALUES || {});
tbl += '<tr class="' + cls + '"><td>' + (c.ROW_NUM||'') + '</td><td>' + (vals.NAME||'') + '</td><td class="num-cell">' + _dc(c,'PRICE') + '</td><td class="num-cell">' + _dc(c,'QTY') + '</td><td class="num-cell">' + _dc(c,'SUM') + '</td><td>' + (vals.DATE_START||'') + '</td></tr>';
});
tbl += '</tbody></table></div>';
diffBody.innerHTML += tbl;
diffBody.innerHTML += '<div style="font-size:12px;color:var(--green);">✓ ' + (e.FILENAME||e.SUPPLEMENT_ID) + ': ' + e.ROWS_SAVED + ' строк</div>';
}
});
// Сравнение
diffBody.innerHTML += '<div style="margin-top:8px;font-weight:600;">📊 Сравнение:</div>';
var all = data.ALL_CHANGES || [];
if (all.length === 0) {
diffBody.innerHTML += '<div style="color:var(--muted);font-size:12px;">Нет допников для сравнения.</div>';
} else {
all.forEach(function(ch) {
var s = ch.SUMMARY || {};
diffBody.innerHTML += '<div style="font-weight:600;margin-top:12px;">📄 Допник (' + ch.TYPE + ')</div>';
diffBody.innerHTML += '<div style="font-size:12px;margin-left:8px;"><span style="color:var(--green);">+' + (s.ADDED||0) + '</span> <span style="color:#eab308;">~' + (s.CHANGED||0) + '</span> <span style="color:var(--destructive);">-' + (s.DELETED||0) + '</span></div>';
diffStatus.textContent = 'изм:' + (s.CHANGED||0) + ' +' + (s.ADDED||0) + ' -' + (s.DELETED||0);
var changes = ch.CHANGES || [];
if (changes.length === 0) {
diffBody.innerHTML += '<div style="color:var(--muted);font-size:12px;">Нет изменений</div>';
} else {
var tbl = '<div class="table-wrap" style="margin-top:4px;"><table><thead><tr><th>№</th><th>Услуга</th><th>Цена</th><th>Объём</th><th>Сумма</th><th>Начало</th></tr></thead><tbody>';
changes.forEach(function(c) {
var cls = c.CHANGE_TYPE === 'added' ? 'diff-added' : c.CHANGE_TYPE === 'deleted' ? 'diff-deleted' : c.CHANGE_TYPE === 'changed' ? 'diff-changed' : '';
var vals = c.NEW_VALUES && Object.keys(c.NEW_VALUES).length > 0 ? c.NEW_VALUES : (c.OLD_VALUES || {});
tbl += '<tr class="' + cls + '"><td>' + (c.ROW_NUM||'') + '</td><td>' + (vals.NAME||'') + '</td><td class="num-cell">' + _dc(c,'PRICE') + '</td><td class="num-cell">' + _dc(c,'QTY') + '</td><td class="num-cell">' + _dc(c,'SUM') + '</td><td>' + (vals.DATE_START||'') + '</td></tr>';
});
tbl += '</tbody></table></div>';
diffBody.innerHTML += tbl;
}
});
}
} else {
diffBody.innerHTML += '<div style="color:var(--destructive);">✗ ' + (data.ERROR||'') + '</div>';
diffBody.innerHTML = '<div style="color:var(--destructive);">✗ ' + (data.ERROR||'Неизвестная ошибка') + '</div>';
}
} catch(e) { diffBody.innerHTML += '<div style="color:var(--destructive);">✗ ' + e.message + '</div>'; }
} catch(e) {
diffBody.innerHTML = '<div style="color:var(--destructive);">✗ ' + e.message + '</div>';
}
clearInterval(timerInterval);
diffStatus.textContent = '✓ ' + ((Date.now() - llmStart) / 1000).toFixed(1) + 'с';