v1.0.174: sync-batch — удаление мусора после загрузки, DELETE /api/documents/<id>

This commit is contained in:
2026-06-24 14:59:46 +04:00
parent 7538c0a5c9
commit b325a6b2c2
2 changed files with 73 additions and 0 deletions
+26
View File
@@ -49,6 +49,22 @@ fileInput.addEventListener('change', async function() {
fileInput.disabled = true; fileInput.disabled = true;
// Удалить из очереди файлы, которых нет в новом выборе
var newNames = new Set(newFiles.map(function(f) { return f.name; }));
var removed = [];
fileQueue = fileQueue.filter(function(f) {
if (!newNames.has(f.name)) { removed.push(f); return false; }
return true;
});
// Удалить с сервера то, что убрали из таблицы
for (var ri = 0; ri < removed.length; ri++) {
var rf = removed[ri];
if (rf.doc_id) {
fetch(VM_API + '/api/documents/' + rf.doc_id + '?contract_id=' + (contractId||''), { method: 'DELETE' }).catch(function(){});
}
}
renderTable();
for (var i = 0; i < newFiles.length; i++) { for (var i = 0; i < newFiles.length; i++) {
var f = newFiles[i]; var f = newFiles[i];
var isZip = f.name.toLowerCase().endsWith('.zip'); var isZip = f.name.toLowerCase().endsWith('.zip');
@@ -168,6 +184,16 @@ fileInput.addEventListener('change', async function() {
await refreshSupps(); await refreshSupps();
// Удалить с сервера мусор — документы этого батча, которых нет в таблице
if (batchId) {
var keepIds = fileQueue.map(function(f) { return f.doc_id; }).filter(Boolean);
fetch(VM_API + '/api/sync-batch', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({batch_id: batchId, keep_ids: keepIds})
}).catch(function(){});
}
fileInput.value = ''; fileInput.value = '';
fileInput.disabled = false; fileInput.disabled = false;
// Показать кнопки после авто-парсинга // Показать кнопки после авто-парсинга
+47
View File
@@ -78,6 +78,15 @@ class Handler(BaseHTTPRequestHandler):
self._handle_api_prompts_activate() self._handle_api_prompts_activate()
elif self.path == "/api/prompts/delete": elif self.path == "/api/prompts/delete":
self._handle_api_prompts_delete() self._handle_api_prompts_delete()
elif self.path == "/api/sync-batch":
self._handle_api_sync_batch()
else:
self.send_error(404)
def do_DELETE(self):
parsed = urlparse(self.path)
if parsed.path.startswith("/api/documents/"):
self._handle_api_document_delete(parsed)
else: else:
self.send_error(404) self.send_error(404)
@@ -139,6 +148,44 @@ class Handler(BaseHTTPRequestHandler):
"elements_json": doc.get("elements_json"), "elements_json": doc.get("elements_json"),
}) })
def _handle_api_document_delete(self, parsed):
"""DELETE /api/documents/<id> — cascade: spec_current, spec_events, supplements, document."""
from db.connection import execute, query
doc_id = parsed.path.split("/")[-1]
supps = query("SELECT id, contract_id FROM supplements WHERE document_id = %s", (doc_id,))
for s in (supps or []):
execute("DELETE FROM spec_current WHERE contract_id = %s", (s["contract_id"],))
execute("DELETE FROM spec_events WHERE supplement_id = %s", (s["id"],))
execute("DELETE FROM supplements WHERE id = %s", (s["id"],))
execute("DELETE FROM documents WHERE id = %s", (doc_id,))
self._json({"ok": True})
# ── POST /api/sync-batch ────────────────────────────────────────────
def _handle_api_sync_batch(self):
"""Удалить все документы батча, НЕ входящие в keep_ids."""
from db.connection import execute, query
length = int(self.headers.get("Content-Length", 0))
body = json.loads(self.rfile.read(length)) if length > 0 else {}
batch_id = body.get("batch_id", "")
keep_ids = set(body.get("keep_ids", []))
if not batch_id:
self._json({"ok": False, "error": "batch_id required"}, 400)
return
docs = query("SELECT id FROM documents WHERE batch_id = %s", (batch_id,))
deleted = 0
for d in (docs or []):
if d["id"] in keep_ids:
continue
supps = query("SELECT id, contract_id FROM supplements WHERE document_id = %s", (d["id"],))
for s in (supps or []):
execute("DELETE FROM spec_current WHERE contract_id = %s", (s["contract_id"],))
execute("DELETE FROM spec_events WHERE supplement_id = %s", (s["id"],))
execute("DELETE FROM supplements WHERE id = %s", (s["id"],))
execute("DELETE FROM documents WHERE id = %s", (d["id"],))
deleted += 1
self._json({"ok": True, "deleted": deleted})
# ── /api/groups ?batch=X ───────────────────────────────────────────── # ── /api/groups ?batch=X ─────────────────────────────────────────────
def _handle_api_groups(self, parsed): def _handle_api_groups(self, parsed):