export
parent
30ae8b76b6
commit
2442599757
57
app.py
57
app.py
|
|
@ -1,9 +1,11 @@
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException, File, UploadFile
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import datetime
|
import datetime
|
||||||
|
import csv
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse, StreamingResponse
|
||||||
|
import io
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
@ -162,6 +164,57 @@ def delete_install(install_id: int):
|
||||||
raise HTTPException(status_code=404, detail="Запись не найдена")
|
raise HTTPException(status_code=404, detail="Запись не найдена")
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
|
# --- CSV Export/Import API ---
|
||||||
|
@app.get("/api/export/csv")
|
||||||
|
async def export_csv():
|
||||||
|
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()
|
||||||
|
|
||||||
|
output = io.StringIO()
|
||||||
|
writer = csv.writer(output, lineterminator='\n')
|
||||||
|
writer.writerow(['ID подключения', 'Имя компьютера', 'Время установки', 'Папка', 'Протокол'])
|
||||||
|
for row in rows:
|
||||||
|
writer.writerow(row)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Content-Disposition': 'attachment; filename="rustdesk_data.csv"',
|
||||||
|
'Content-Type': 'text/csv'
|
||||||
|
}
|
||||||
|
return StreamingResponse(iter([output.getvalue()]), headers=headers)
|
||||||
|
|
||||||
|
@app.post("/api/import/csv")
|
||||||
|
async def import_csv(file: UploadFile = File(...)):
|
||||||
|
try:
|
||||||
|
contents = await file.read()
|
||||||
|
csv_data = io.StringIO(contents.decode('utf-8'))
|
||||||
|
reader = csv.DictReader(csv_data)
|
||||||
|
|
||||||
|
for row in reader:
|
||||||
|
rust_id = row['ID подключения']
|
||||||
|
computer_name = row['Имя компьютера']
|
||||||
|
install_time = row['Время установки']
|
||||||
|
folder_name = row['Папка']
|
||||||
|
protocol = row['Протокол'] or 'rustdesk'
|
||||||
|
|
||||||
|
# Получаем или создаем ID папки
|
||||||
|
cursor.execute("SELECT id FROM folders WHERE name = ?", (folder_name,))
|
||||||
|
folder = cursor.fetchone()
|
||||||
|
folder_id = folder[0] if folder else unsorted_folder_id
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO installs (rust_id, computer_name, install_time, folder_id, protocol)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
""", (rust_id, computer_name, install_time, folder_id, protocol))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
return {"status": "success", "message": "Данные успешно импортированы"}
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Ошибка импорта: {str(e)}")
|
||||||
|
|
||||||
# CORS
|
# CORS
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,10 @@
|
||||||
.sort-arrow { font-size: 12px; margin-left: 5px; }
|
.sort-arrow { font-size: 12px; margin-left: 5px; }
|
||||||
.protocol-icon { margin-right: 5px; height: 16px; width: 16px; vertical-align: middle; }
|
.protocol-icon { margin-right: 5px; height: 16px; width: 16px; vertical-align: middle; }
|
||||||
.connection-link { color: blue; text-decoration: underline; cursor: pointer; }
|
.connection-link { color: blue; text-decoration: underline; cursor: pointer; }
|
||||||
|
#import-form { margin-top: 10px; }
|
||||||
|
#import-file { display: none; }
|
||||||
|
#import-label { cursor: pointer; background: #007bff; color: white; padding: 5px 10px; border-radius: 5px; }
|
||||||
|
#import-label:hover { background: #0056b3; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -41,6 +45,13 @@
|
||||||
<input type="radio" id="search-all" name="search-scope" value="all">
|
<input type="radio" id="search-all" name="search-scope" value="all">
|
||||||
<label for="search-all">Все папки</label>
|
<label for="search-all">Все папки</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
<button onclick="exportCSV()">Экспорт CSV</button>
|
||||||
|
<form id="import-form" enctype="multipart/form-data">
|
||||||
|
<input type="file" id="import-file" accept=".csv" onchange="importCSV(this.files[0])">
|
||||||
|
<label for="import-file" id="import-label">Импорт CSV</label>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<h2>Добавить запись</h2>
|
<h2>Добавить запись</h2>
|
||||||
|
|
@ -344,6 +355,32 @@
|
||||||
window.location.href = link;
|
window.location.href = link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportCSV() {
|
||||||
|
window.location.href = `${API_URL}/export/csv`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function importCSV(file) {
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/import/csv`,
|
||||||
|
type: 'POST',
|
||||||
|
data: formData,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success: function (response) {
|
||||||
|
alert(response.message);
|
||||||
|
loadInstalls(selectedFolderId);
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
alert(`Ошибка импорта: ${xhr.responseJSON.detail || error}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue