217 lines
6.8 KiB
HTML
217 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Batch Upload - CSV & Bilder</title>
|
|
<style>
|
|
:root {
|
|
--primary-color: #4a90e2;
|
|
--background-color: #f4f7f6;
|
|
--text-color: #333;
|
|
--border-radius: 8px;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background-color: var(--background-color);
|
|
color: var(--text-color);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
min-height: 100vh;
|
|
margin: 0;
|
|
}
|
|
|
|
.upload-container {
|
|
background: white;
|
|
padding: 2rem;
|
|
border-radius: var(--border-radius);
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
width: 100%;
|
|
max-width: 500px;
|
|
}
|
|
|
|
h2 {
|
|
margin-top: 0;
|
|
color: var(--primary-color);
|
|
text-align: center;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
font-weight: 600;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
input[type="file"] {
|
|
display: block;
|
|
width: 100%;
|
|
padding: 0.5rem;
|
|
border: 1px dashed #ccc;
|
|
border-radius: var(--border-radius);
|
|
background: #fafafa;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.btn-submit {
|
|
width: 100%;
|
|
padding: 0.75rem;
|
|
background-color: var(--primary-color);
|
|
color: white;
|
|
border: none;
|
|
border-radius: var(--border-radius);
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.btn-submit:hover {
|
|
background-color: #357abd;
|
|
}
|
|
|
|
.btn-submit:disabled {
|
|
background-color: #a0c4e8;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Status & Feedback Messages */
|
|
#status-message {
|
|
margin-top: 1rem;
|
|
padding: 1rem;
|
|
border-radius: var(--border-radius);
|
|
display: none;
|
|
text-align: center;
|
|
}
|
|
|
|
.success {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
border: 1px solid #c3e6cb;
|
|
}
|
|
|
|
.error {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
border: 1px solid #f5c6cb;
|
|
}
|
|
|
|
.loading {
|
|
background-color: #e2e3e5;
|
|
color: #383d41;
|
|
border: 1px solid #d6d8db;
|
|
}
|
|
|
|
.spinner {
|
|
display: inline-block;
|
|
width: 1.5rem;
|
|
height: 1.5rem;
|
|
border: 3px solid rgba(0,0,0,0.1);
|
|
border-radius: 50%;
|
|
border-top-color: var(--primary-color);
|
|
animation: spin 1s ease-in-out infinite;
|
|
vertical-align: middle;
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="upload-container">
|
|
<h2>Inventar Batch Upload</h2>
|
|
|
|
<form id="uploadForm">
|
|
<div class="form-group">
|
|
<label for="csv_file">1. items.csv Datei auswählen</label>
|
|
<!-- Akzeptiert nur CSV Dateien -->
|
|
<input type="file" id="csv_file" name="csv_file" accept=".csv" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="images">2. Bilder auswählen</label>
|
|
<!-- multiple erlaubt das Auswählen mehrerer Bilder gleichzeitig -->
|
|
<input type="file" id="images" name="images" accept="image/*" multiple required>
|
|
<small style="color: #666; display: block; margin-top: 5px;">Du kannst mehrere Bilder markieren (Strg/Cmd gedrückt halten).</small>
|
|
</div>
|
|
|
|
<button type="submit" id="submitBtn" class="btn-submit">Daten hochladen</button>
|
|
</form>
|
|
|
|
<div id="status-message"></div>
|
|
</div>
|
|
|
|
<script>
|
|
document.getElementById('uploadForm').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const form = e.target;
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
const statusDiv = document.getElementById('status-message');
|
|
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerText = 'Wird verarbeitet...';
|
|
statusDiv.className = 'loading';
|
|
statusDiv.style.display = 'block';
|
|
statusDiv.innerHTML = '<div class="spinner"></div> Lade Dateien hoch und verarbeite Bilder... Bitte warten.';
|
|
|
|
const formData = new FormData(form);
|
|
|
|
const fetchOptions = {
|
|
method: 'POST',
|
|
body: formData,
|
|
credentials: 'include',
|
|
headers: {
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
};
|
|
|
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
|
|
|
if (csrfToken) {
|
|
fetchOptions.headers = {
|
|
'X-CSRFToken': csrfToken
|
|
};
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/upload_csv_batch', fetchOptions);
|
|
|
|
// Antwort einmalig als Text auslesen, um sowohl JSON als auch HTML-Fehler abzufangen
|
|
const responseText = await response.text();
|
|
|
|
let result;
|
|
try {
|
|
result = JSON.parse(responseText);
|
|
} catch (jsonError) {
|
|
console.error("Server hat kein JSON gesendet. Antwort war:", responseText);
|
|
throw new Error("Der Server hat einen HTML-Fehler zurückgegeben (z.B. Nginx 413 Entity Too Large oder Server-Crash). Siehe F12 Konsole.");
|
|
}
|
|
|
|
if (response.ok && result.success) {
|
|
statusDiv.className = 'success';
|
|
statusDiv.innerHTML = `<strong>Erfolg!</strong><br>${result.message}`;
|
|
form.reset();
|
|
} else {
|
|
statusDiv.className = 'error';
|
|
statusDiv.innerHTML = `<strong>Fehler:</strong> ${result.message || 'Ein unbekannter Fehler ist aufgetreten.'}`;
|
|
}
|
|
|
|
} catch (error) {
|
|
statusDiv.className = 'error';
|
|
statusDiv.innerHTML = `<strong>Fehler:</strong> ${error.message}`;
|
|
console.error('Upload Error:', error);
|
|
} finally {
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerText = 'Daten hochladen';
|
|
}
|
|
});
|
|
</script> |