radio для выбора базового договора + api set_initial (v1.0.57)

This commit is contained in:
2026-06-19 10:27:10 +04:00
parent bde4ccefea
commit f99fae5a28
2 changed files with 66 additions and 3 deletions
+25
View File
@@ -117,6 +117,31 @@
<cfset body = deserializeJSON(toString(getHttpRequestData().content))> <cfset body = deserializeJSON(toString(getHttpRequestData().content))>
<cfquery datasource="baza">#preserveSingleQuotes(body.sql)#</cfquery> <cfquery datasource="baza">#preserveSingleQuotes(body.sql)#</cfquery>
<cfset result = {ok: true}> <cfset result = {ok: true}>
<cfelseif url.action EQ "set_initial">
<cfparam name="url.supplement_id" default="">
<cfif NOT len(url.supplement_id)>
<cfset result = {ok: false, error: "supplement_id required"}>
<cfelse>
<cfquery name="sup" datasource="baza">
SELECT contract_id FROM supplements WHERE id=<cfqueryparam value="#url.supplement_id#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfif sup.recordCount EQ 0>
<cfset result = {ok: false, error: "supplement not found"}>
<cfelse>
<cftransaction>
<cfquery datasource="baza">
UPDATE supplements SET type='additional'
WHERE contract_id=<cfqueryparam value="#sup.contract_id#" cfsqltype="cf_sql_varchar">
</cfquery>
<cfquery datasource="baza">
UPDATE supplements SET type='initial'
WHERE id=<cfqueryparam value="#url.supplement_id#" cfsqltype="cf_sql_varchar">
</cfquery>
</cftransaction>
<cfset result = {ok: true}>
</cfif>
</cfif>
</cfif> </cfif>
<cfcatch> <cfcatch>
+41 -3
View File
@@ -61,7 +61,7 @@
<body> <body>
<div class="topbar"> <div class="topbar">
<img src="/nubes-logo.svg" alt="Nubes"> <img src="/nubes-logo.svg" alt="Nubes">
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.56 — Lucee</span></span> <span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.57 — Lucee</span></span>
</div> </div>
<div class="content"> <div class="content">
@@ -76,7 +76,7 @@
<div class="table-wrap"> <div class="table-wrap">
<table> <table>
<thead> <thead>
<tr><th>Имя</th><th style="width:130px;">Изменён</th><th style="width:90px;">Размер</th><th style="width:115px;">Статус</th><th style="width:30px;"></th><th style="width:30px;"></th></tr> <tr><th>Имя</th><th style="width:130px;">Изменён</th><th style="width:90px;">Размер</th><th style="width:115px;">Статус</th><th style="width:30px;">Базовый</th><th style="width:30px;"></th><th style="width:30px;"></th></tr>
</thead> </thead>
<tbody id="fileTable"></tbody> <tbody id="fileTable"></tbody>
</table> </table>
@@ -164,15 +164,20 @@ function formatDate(ts) {
function renderTable() { function renderTable() {
if (fileQueue.length === 0) { if (fileQueue.length === 0) {
fileTable.innerHTML = '<tr class="empty-row"><td colspan="6">Нет файлов — выберите .docx / .pdf / .zip</td></tr>'; fileTable.innerHTML = '<tr class="empty-row"><td colspan="7">Нет файлов — выберите .docx / .pdf / .zip</td></tr>';
parseBtn.disabled = true; parseBtn.disabled = true;
} else { } else {
fileTable.innerHTML = fileQueue.map(function(f, i) { fileTable.innerHTML = fileQueue.map(function(f, i) {
var radio = '';
if (f.supp_id) {
radio = '<input type="radio" name="base_doc" value="' + f.supp_id + '"' + (f.supp_type === 'initial' ? ' checked' : '') + ' onchange="setInitial(\'' + f.supp_id + '\')" title="Выбрать как базовый договор">';
}
return '<tr id="row_' + i + '">' + return '<tr id="row_' + i + '">' +
'<td class="name-cell">' + f.name + '</td>' + '<td class="name-cell">' + f.name + '</td>' +
'<td style="font-size:12px;color:var(--muted);">' + formatDate(f.lastModified) + '</td>' + '<td style="font-size:12px;color:var(--muted);">' + formatDate(f.lastModified) + '</td>' +
'<td class="num-cell" style="font-size:12px;color:var(--muted);">' + formatSize(f.size) + '</td>' + '<td class="num-cell" style="font-size:12px;color:var(--muted);">' + formatSize(f.size) + '</td>' +
'<td class="status-cell">' + (f.status || '') + '</td>' + '<td class="status-cell">' + (f.status || '') + '</td>' +
'<td style="text-align:center;">' + radio + '</td>' +
'<td><button class="info-btn' + (f.doc_id ? ' visible' : '') + '" id="info_' + i + '" onclick="showInfo(' + i + ')" title="Инфо"><i data-lucide="info" style="width:16px;height:16px;"></i></button></td>' + '<td><button class="info-btn' + (f.doc_id ? ' visible' : '') + '" id="info_' + i + '" onclick="showInfo(' + i + ')" title="Инфо"><i data-lucide="info" style="width:16px;height:16px;"></i></button></td>' +
'<td><button class="remove-btn" onclick="removeFile(' + i + ')" title="Удалить"><i data-lucide="trash-2" style="width:16px;height:16px;"></i></button></td>' + '<td><button class="remove-btn" onclick="removeFile(' + i + ')" title="Удалить"><i data-lucide="trash-2" style="width:16px;height:16px;"></i></button></td>' +
'</tr>'; '</tr>';
@@ -219,6 +224,8 @@ fileInput.addEventListener('change', async function() {
renderTable(); renderTable();
} }
await refreshSupps();
fileInput.value = ''; fileInput.value = '';
fileInput.disabled = false; fileInput.disabled = false;
parseBtn.disabled = (contractId === null); parseBtn.disabled = (contractId === null);
@@ -304,6 +311,9 @@ parseBtn.addEventListener('click', async function() {
renderTable(); renderTable();
} }
// Обновить информацию о supplement_id/type для radio
await refreshSupps();
parseBtn.innerHTML = '<i data-lucide="check" style="width:16px;height:16px;"></i> ✓ Готово'; parseBtn.innerHTML = '<i data-lucide="check" style="width:16px;height:16px;"></i> ✓ Готово';
var llmBtn = document.getElementById('llmBtn'); var llmBtn = document.getElementById('llmBtn');
llmBtn.style.display = 'flex'; llmBtn.style.display = 'flex';
@@ -311,6 +321,34 @@ parseBtn.addEventListener('click', async function() {
lucide.createIcons(); lucide.createIcons();
}); });
// ── Обновить supplement_id/type для radio ──────────────────
async function refreshSupps() {
if (!contractId) return;
try {
var resp = await fetch('/api.cfm?action=query&sql=' + encodeURIComponent("SELECT s.id, s.type, s.document_id FROM supplements s WHERE s.contract_id='" + contractId + "'"));
var data = await resp.json();
if (data.OK && data.ROWS) {
data.ROWS.forEach(function(r) {
var supp = {};
data.COLUMNS.forEach(function(c, ci) { supp[c] = r[ci]; });
for (var i = 0; i < fileQueue.length; i++) {
if (fileQueue[i].doc_id === supp.document_id) {
fileQueue[i].supp_id = supp.id;
fileQueue[i].supp_type = supp.type;
}
}
});
renderTable();
}
} catch(e) {}
}
function setInitial(suppId) {
fetch('/api.cfm?action=set_initial&supplement_id=' + suppId)
.then(function() { refreshSupps(); });
}
window.setInitial = setInitial;
// ── LLM: Сравнить ──────────────────────────────────────────── // ── LLM: Сравнить ────────────────────────────────────────────
document.getElementById('llmBtn').addEventListener('click', async function() { document.getElementById('llmBtn').addEventListener('click', async function() {
if (!contractId) return; if (!contractId) return;