export check

main
Satur@it-depot.ru 2025-03-05 10:52:50 +03:00
parent 270fa3ace5
commit 9360a1a671
2 changed files with 48 additions and 14 deletions

44
app.py
View File

@ -1,4 +1,4 @@
from fastapi import FastAPI, HTTPException, File, UploadFile from fastapi import FastAPI, HTTPException, File, UploadFile, Query
from pydantic import BaseModel from pydantic import BaseModel
import sqlite3 import sqlite3
import datetime import datetime
@ -166,12 +166,20 @@ def delete_install(install_id: int):
# --- CSV Export/Import API --- # --- CSV Export/Import API ---
@app.get("/api/export/csv") @app.get("/api/export/csv")
async def export_csv(): async def export_csv(folder_id: int | None = Query(None, description="ID папки для экспорта, если None - экспортировать все папки")):
cursor.execute(""" if folder_id:
SELECT i.rust_id, i.computer_name, i.install_time, f.name as folder_name, i.protocol cursor.execute("""
FROM installs i SELECT i.rust_id, i.computer_name, i.install_time, f.name as folder_name, i.protocol
LEFT JOIN folders f ON i.folder_id = f.id FROM installs i
""") LEFT JOIN folders f ON i.folder_id = f.id
WHERE i.folder_id = ?
""", (folder_id,))
else:
cursor.execute("""
SELECT i.rust_id, i.computer_name, i.install_time, f.name as folder_name, i.protocol
FROM installs i
LEFT JOIN folders f ON i.folder_id = f.id
""")
rows = cursor.fetchall() rows = cursor.fetchall()
output = io.StringIO() output = io.StringIO()
@ -187,23 +195,33 @@ async def export_csv():
return StreamingResponse(iter([output.getvalue()]), headers=headers) return StreamingResponse(iter([output.getvalue()]), headers=headers)
@app.post("/api/import/csv") @app.post("/api/import/csv")
async def import_csv(file: UploadFile = File(...)): async def import_csv(file: UploadFile = File(...), folder_id: int | None = Query(None, description="ID папки для импорта, если None - использовать 'Несортированные'")):
try: try:
contents = await file.read() contents = await file.read()
csv_data = io.StringIO(contents.decode('utf-8')) csv_data = io.StringIO(contents.decode('utf-8'))
reader = csv.DictReader(csv_data) reader = csv.DictReader(csv_data)
target_folder_id = folder_id if folder_id is not None else unsorted_folder_id
for row in reader: for row in reader:
rust_id = row['ID подключения'] rust_id = row['ID подключения']
computer_name = row['Имя компьютера'] computer_name = row['Имя компьютера']
install_time = row['Время установки'] install_time = row['Время установки']
folder_name = row['Папка'] folder_name = row.get('Папка', None)
protocol = row['Протокол'] or 'rustdesk' protocol = row.get('Протокол', 'rustdesk')
# Проверяем, существует ли запись с таким rust_id
cursor.execute("SELECT id FROM installs WHERE rust_id = ?", (rust_id,))
if cursor.fetchone():
continue # Пропускаем дублирующуюся запись
# Получаем или создаем ID папки # Получаем или создаем ID папки
cursor.execute("SELECT id FROM folders WHERE name = ?", (folder_name,)) if folder_name:
folder = cursor.fetchone() cursor.execute("SELECT id FROM folders WHERE name = ?", (folder_name,))
folder_id = folder[0] if folder else unsorted_folder_id folder = cursor.fetchone()
folder_id = folder[0] if folder else unsorted_folder_id
else:
folder_id = target_folder_id
cursor.execute(""" cursor.execute("""
INSERT INTO installs (rust_id, computer_name, install_time, folder_id, protocol) INSERT INTO installs (rust_id, computer_name, install_time, folder_id, protocol)

View File

@ -27,6 +27,7 @@
#import-file { display: none; } #import-file { display: none; }
#import-label { cursor: pointer; background: #007bff; color: white; padding: 5px 10px; border-radius: 5px; } #import-label { cursor: pointer; background: #007bff; color: white; padding: 5px 10px; border-radius: 5px; }
#import-label:hover { background: #0056b3; } #import-label:hover { background: #0056b3; }
.folder-select { margin: 5px 0; }
</style> </style>
</head> </head>
<body> <body>
@ -46,6 +47,9 @@
<label for="search-all">Все папки</label> <label for="search-all">Все папки</label>
</div> </div>
<div style="margin-top: 10px;"> <div style="margin-top: 10px;">
<select id="folder-select" class="folder-select">
<option value="">Все папки</option>
</select>
<button onclick="exportCSV()">Экспорт CSV</button> <button onclick="exportCSV()">Экспорт CSV</button>
<form id="import-form" enctype="multipart/form-data"> <form id="import-form" enctype="multipart/form-data">
<input type="file" id="import-file" accept=".csv" onchange="importCSV(this.files[0])"> <input type="file" id="import-file" accept=".csv" onchange="importCSV(this.files[0])">
@ -108,6 +112,13 @@
const unsortedFolder = folders.find(f => f.name === 'Несортированные'); const unsortedFolder = folders.find(f => f.name === 'Несортированные');
const unsortedFolderId = unsortedFolder ? unsortedFolder.id : null; const unsortedFolderId = unsortedFolder ? unsortedFolder.id : null;
// Заполняем выпадающий список папок
const $folderSelect = $('#folder-select');
$folderSelect.append('<option value="">Все папки</option>');
folders.forEach(folder => {
$folderSelect.append(`<option value="${folder.id}">${folder.name}</option>`);
});
// Инициализация дерева папок // Инициализация дерева папок
$('#folder-tree').jstree({ $('#folder-tree').jstree({
'core': { 'core': {
@ -357,14 +368,19 @@
} }
function exportCSV() { function exportCSV() {
window.location.href = `${API_URL}/export/csv`; const folderId = $('#folder-select').val() || '';
window.location.href = `${API_URL}/export/csv?folder_id=${folderId}`;
} }
function importCSV(file) { function importCSV(file) {
if (!file) return; if (!file) return;
const folderId = $('#folder-select').val() || '';
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
if (folderId) {
formData.append('folder_id', folderId);
}
$.ajax({ $.ajax({
url: `${API_URL}/import/csv`, url: `${API_URL}/import/csv`,