856 lines
29 KiB
HTML
856 lines
29 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>PowerToolsX - Foto-Upload</title>
|
|
<style>
|
|
:root {
|
|
--bg-primary: #1E1E1E;
|
|
--bg-secondary: #2D2D30;
|
|
--bg-tertiary: #3C3C3C;
|
|
--text-primary: #E0E0E0;
|
|
--text-secondary: #A0A0A0;
|
|
--accent: #0E639C;
|
|
--accent-hover: #1177BB;
|
|
--success: #00B454;
|
|
--warning: #FFB900;
|
|
--error: #E81123;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: var(--bg-primary);
|
|
color: var(--text-primary);
|
|
min-height: 100vh;
|
|
padding: 16px;
|
|
}
|
|
|
|
.container {
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
header {
|
|
text-align: center;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
header h1 {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
header .projekt-name {
|
|
color: var(--accent);
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.section {
|
|
background: var(--bg-secondary);
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 0.9rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 12px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
/* IFC-Hierarchie Dropdowns */
|
|
.ifc-select-group {
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.ifc-select-group label {
|
|
display: block;
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.ifc-select-group select {
|
|
width: 100%;
|
|
padding: 12px;
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid #555;
|
|
border-radius: 6px;
|
|
color: var(--text-primary);
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.ifc-select-group select:disabled {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.ifc-path {
|
|
background: var(--bg-tertiary);
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 8px;
|
|
}
|
|
|
|
/* PropertySets */
|
|
.pset-group {
|
|
border: 1px solid #444;
|
|
border-radius: 6px;
|
|
padding: 12px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.pset-group h4 {
|
|
font-size: 0.9rem;
|
|
margin-bottom: 8px;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.pset-property {
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.pset-property label {
|
|
display: block;
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 2px;
|
|
}
|
|
|
|
.pset-property select,
|
|
.pset-property input {
|
|
width: 100%;
|
|
padding: 8px;
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid #555;
|
|
border-radius: 4px;
|
|
color: var(--text-primary);
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
/* Foto-Capture */
|
|
.capture-area {
|
|
text-align: center;
|
|
}
|
|
|
|
.camera-preview {
|
|
width: 100%;
|
|
max-height: 300px;
|
|
background: #000;
|
|
border-radius: 8px;
|
|
margin-bottom: 12px;
|
|
display: none;
|
|
}
|
|
|
|
.preview-image {
|
|
width: 100%;
|
|
max-height: 300px;
|
|
object-fit: contain;
|
|
border-radius: 8px;
|
|
margin-bottom: 12px;
|
|
display: none;
|
|
}
|
|
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 14px 24px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
gap: 8px;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: var(--accent);
|
|
color: white;
|
|
width: 100%;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background: var(--accent-hover);
|
|
}
|
|
|
|
.btn-primary:disabled {
|
|
background: #555;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.btn-success {
|
|
background: var(--success);
|
|
color: white;
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: var(--bg-tertiary);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.btn-row {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-top: 12px;
|
|
}
|
|
|
|
.btn-row .btn {
|
|
flex: 1;
|
|
}
|
|
|
|
/* Beschreibung */
|
|
textarea {
|
|
width: 100%;
|
|
padding: 12px;
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid #555;
|
|
border-radius: 6px;
|
|
color: var(--text-primary);
|
|
font-size: 1rem;
|
|
resize: vertical;
|
|
min-height: 80px;
|
|
}
|
|
|
|
/* Status */
|
|
.status {
|
|
text-align: center;
|
|
padding: 12px;
|
|
border-radius: 6px;
|
|
margin-top: 16px;
|
|
}
|
|
|
|
.status.success {
|
|
background: rgba(0, 180, 84, 0.2);
|
|
color: var(--success);
|
|
}
|
|
|
|
.status.error {
|
|
background: rgba(232, 17, 35, 0.2);
|
|
color: var(--error);
|
|
}
|
|
|
|
.status.info {
|
|
background: rgba(14, 99, 156, 0.2);
|
|
color: var(--accent);
|
|
}
|
|
|
|
/* Upload Counter */
|
|
.upload-counter {
|
|
text-align: center;
|
|
font-size: 0.9rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 16px;
|
|
}
|
|
|
|
.upload-counter strong {
|
|
color: var(--success);
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
/* Hidden file input */
|
|
#fileInput {
|
|
display: none;
|
|
}
|
|
|
|
/* Loading Overlay */
|
|
.loading-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.8);
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.loading-overlay.active {
|
|
display: flex;
|
|
}
|
|
|
|
.spinner {
|
|
width: 48px;
|
|
height: 48px;
|
|
border: 4px solid var(--bg-tertiary);
|
|
border-top-color: var(--accent);
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
/* No Session */
|
|
.no-session {
|
|
text-align: center;
|
|
padding: 48px 24px;
|
|
}
|
|
|
|
.no-session h2 {
|
|
margin-bottom: 16px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<header>
|
|
<h1>PowerToolsX Foto-Upload</h1>
|
|
<div class="projekt-name" id="projektName">Wird geladen...</div>
|
|
</header>
|
|
|
|
<div id="noSession" class="no-session" style="display: none;">
|
|
<h2>Keine aktive Session</h2>
|
|
<p>Bitte scannen Sie den QR-Code in PowerToolsX um eine Upload-Session zu starten.</p>
|
|
</div>
|
|
|
|
<div id="mainContent" style="display: none;">
|
|
<!-- IFC-Struktur Auswahl -->
|
|
<div class="section">
|
|
<div class="section-title">Ort im Bauwerk</div>
|
|
|
|
<div class="ifc-select-group">
|
|
<label>Gebaude</label>
|
|
<select id="selectBuilding" onchange="onBuildingChanged()">
|
|
<option value="">-- Gebaude wahlen --</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="ifc-select-group">
|
|
<label>Geschoss</label>
|
|
<select id="selectStorey" onchange="onStoreyChanged()" disabled>
|
|
<option value="">-- Geschoss wahlen --</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="ifc-select-group">
|
|
<label>Raum</label>
|
|
<select id="selectSpace" onchange="onSpaceChanged()" disabled>
|
|
<option value="">-- Raum wahlen --</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="ifc-path" id="ifcPath" style="display: none;">
|
|
<strong>Pfad:</strong> <span id="pathText"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- PropertySets -->
|
|
<div class="section" id="propertySetsSection">
|
|
<div class="section-title">Eigenschaften</div>
|
|
<div id="propertySetsContainer"></div>
|
|
</div>
|
|
|
|
<!-- Beschreibung -->
|
|
<div class="section">
|
|
<div class="section-title">Beschreibung</div>
|
|
<textarea id="description" placeholder="Optionale Beschreibung zum Foto..."></textarea>
|
|
</div>
|
|
|
|
<!-- Foto aufnehmen -->
|
|
<div class="section">
|
|
<div class="section-title">Foto</div>
|
|
<div class="capture-area">
|
|
<video id="cameraPreview" class="camera-preview" autoplay playsinline></video>
|
|
<img id="previewImage" class="preview-image" alt="Vorschau">
|
|
|
|
<input type="file" id="fileInput" accept="image/*" capture="environment" onchange="onFileSelected(event)">
|
|
|
|
<button class="btn btn-primary" id="btnCapture" onclick="openCamera()">
|
|
<span>Foto aufnehmen</span>
|
|
</button>
|
|
|
|
<div class="btn-row" id="previewButtons" style="display: none;">
|
|
<button class="btn btn-secondary" onclick="resetCapture()">Neu</button>
|
|
<button class="btn btn-success" onclick="uploadPhoto()">Hochladen</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div id="statusMessage" class="status info" style="display: none;"></div>
|
|
|
|
<!-- Upload Counter -->
|
|
<div class="upload-counter">
|
|
Hochgeladene Fotos: <strong id="uploadCount">0</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Loading Overlay -->
|
|
<div class="loading-overlay" id="loadingOverlay">
|
|
<div class="spinner"></div>
|
|
</div>
|
|
|
|
<script>
|
|
// Konfiguration
|
|
const DATA_URL = 'https://docs.artetui.de/backups/fotoupload';
|
|
|
|
// Session-Daten
|
|
let sessionId = null;
|
|
let strukturData = null;
|
|
let selectedElement = null;
|
|
let capturedImageData = null;
|
|
let uploadCount = 0;
|
|
|
|
// Initialisierung
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
// Session-ID aus URL holen
|
|
const params = new URLSearchParams(window.location.search);
|
|
sessionId = params.get('session');
|
|
|
|
if (!sessionId) {
|
|
document.getElementById('noSession').style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
// Struktur laden
|
|
await loadStruktur();
|
|
});
|
|
|
|
// IFC-Struktur vom Server laden
|
|
async function loadStruktur() {
|
|
showLoading(true);
|
|
try {
|
|
const response = await fetch(`${DATA_URL}/struktur_${sessionId}.json`);
|
|
if (!response.ok) {
|
|
throw new Error('Struktur nicht gefunden');
|
|
}
|
|
|
|
strukturData = await response.json();
|
|
|
|
// UI aktualisieren
|
|
document.getElementById('projektName').textContent = strukturData.ProjektName || 'Projekt';
|
|
document.getElementById('mainContent').style.display = 'block';
|
|
|
|
// Gebaude-Dropdown fullen
|
|
populateBuildingSelect();
|
|
|
|
// PropertySets generieren
|
|
generatePropertySets();
|
|
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Struktur:', error);
|
|
document.getElementById('projektName').textContent = 'Fehler beim Laden';
|
|
showStatus('Struktur konnte nicht geladen werden. Bitte erneut versuchen.', 'error');
|
|
document.getElementById('mainContent').style.display = 'block';
|
|
} finally {
|
|
showLoading(false);
|
|
}
|
|
}
|
|
|
|
// Gebaude-Dropdown fullen
|
|
function populateBuildingSelect() {
|
|
const select = document.getElementById('selectBuilding');
|
|
select.innerHTML = '<option value="">-- Gebaude wahlen --</option>';
|
|
|
|
if (!strukturData || !strukturData.Elemente) return;
|
|
|
|
// Finde alle IfcBuilding Elemente
|
|
const buildings = findElementsByType(strukturData.Elemente, 'IfcBuilding');
|
|
|
|
buildings.forEach(b => {
|
|
const option = document.createElement('option');
|
|
option.value = b.GlobalId;
|
|
option.textContent = `${b.Icon || ''} ${b.Name}`;
|
|
option.dataset.element = JSON.stringify(b);
|
|
select.appendChild(option);
|
|
});
|
|
}
|
|
|
|
// Rekursiv Elemente nach Typ finden
|
|
function findElementsByType(elements, type) {
|
|
let result = [];
|
|
for (const el of elements) {
|
|
if (el.IfcType === type) {
|
|
result.push(el);
|
|
}
|
|
if (el.Children && el.Children.length > 0) {
|
|
result = result.concat(findElementsByType(el.Children, type));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Element nach GlobalId finden
|
|
function findElementById(elements, globalId) {
|
|
for (const el of elements) {
|
|
if (el.GlobalId === globalId) {
|
|
return el;
|
|
}
|
|
if (el.Children && el.Children.length > 0) {
|
|
const found = findElementById(el.Children, globalId);
|
|
if (found) return found;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Gebaude geandert
|
|
function onBuildingChanged() {
|
|
const select = document.getElementById('selectBuilding');
|
|
const storeySelect = document.getElementById('selectStorey');
|
|
const spaceSelect = document.getElementById('selectSpace');
|
|
|
|
// Geschoss und Raum zurucksetzen
|
|
storeySelect.innerHTML = '<option value="">-- Geschoss wahlen --</option>';
|
|
storeySelect.disabled = true;
|
|
spaceSelect.innerHTML = '<option value="">-- Raum wahlen --</option>';
|
|
spaceSelect.disabled = true;
|
|
selectedElement = null;
|
|
updatePath();
|
|
|
|
if (!select.value) return;
|
|
|
|
// Gebaude finden
|
|
const building = findElementById(strukturData.Elemente, select.value);
|
|
if (!building) return;
|
|
|
|
// Geschosse dieses Gebaudes finden
|
|
const storeys = findElementsByType(building.Children || [], 'IfcBuildingStorey');
|
|
|
|
storeys.forEach(s => {
|
|
const option = document.createElement('option');
|
|
option.value = s.GlobalId;
|
|
option.textContent = `${s.Icon || ''} ${s.Name}`;
|
|
option.dataset.element = JSON.stringify(s);
|
|
storeySelect.appendChild(option);
|
|
});
|
|
|
|
storeySelect.disabled = storeys.length === 0;
|
|
}
|
|
|
|
// Geschoss geandert
|
|
function onStoreyChanged() {
|
|
const buildingSelect = document.getElementById('selectBuilding');
|
|
const storeySelect = document.getElementById('selectStorey');
|
|
const spaceSelect = document.getElementById('selectSpace');
|
|
|
|
// Raum zurucksetzen
|
|
spaceSelect.innerHTML = '<option value="">-- Raum wahlen --</option>';
|
|
spaceSelect.disabled = true;
|
|
|
|
if (!storeySelect.value) {
|
|
selectedElement = null;
|
|
updatePath();
|
|
return;
|
|
}
|
|
|
|
// Gebaude und Geschoss finden
|
|
const building = findElementById(strukturData.Elemente, buildingSelect.value);
|
|
const storey = findElementById(building?.Children || [], storeySelect.value);
|
|
|
|
if (!storey) {
|
|
selectedElement = null;
|
|
updatePath();
|
|
return;
|
|
}
|
|
|
|
// Raume dieses Geschosses finden
|
|
const spaces = findElementsByType(storey.Children || [], 'IfcSpace');
|
|
|
|
spaces.forEach(s => {
|
|
const option = document.createElement('option');
|
|
option.value = s.GlobalId;
|
|
option.textContent = `${s.Icon || ''} ${s.Name}`;
|
|
option.dataset.element = JSON.stringify(s);
|
|
spaceSelect.appendChild(option);
|
|
});
|
|
|
|
spaceSelect.disabled = spaces.length === 0;
|
|
|
|
// Geschoss als ausgewahltes Element setzen (falls kein Raum gewahlt)
|
|
selectedElement = storey;
|
|
updatePath();
|
|
}
|
|
|
|
// Raum geandert
|
|
function onSpaceChanged() {
|
|
const buildingSelect = document.getElementById('selectBuilding');
|
|
const storeySelect = document.getElementById('selectStorey');
|
|
const spaceSelect = document.getElementById('selectSpace');
|
|
|
|
if (!spaceSelect.value) {
|
|
// Zurück zum Geschoss
|
|
const building = findElementById(strukturData.Elemente, buildingSelect.value);
|
|
selectedElement = findElementById(building?.Children || [], storeySelect.value);
|
|
} else {
|
|
// Raum finden
|
|
const building = findElementById(strukturData.Elemente, buildingSelect.value);
|
|
const storey = findElementById(building?.Children || [], storeySelect.value);
|
|
selectedElement = findElementById(storey?.Children || [], spaceSelect.value);
|
|
}
|
|
updatePath();
|
|
}
|
|
|
|
// Pfad-Anzeige aktualisieren
|
|
function updatePath() {
|
|
const pathDiv = document.getElementById('ifcPath');
|
|
const pathText = document.getElementById('pathText');
|
|
|
|
if (!selectedElement) {
|
|
pathDiv.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// Pfad aus den Dropdowns bauen
|
|
const parts = [];
|
|
const buildingSelect = document.getElementById('selectBuilding');
|
|
const storeySelect = document.getElementById('selectStorey');
|
|
const spaceSelect = document.getElementById('selectSpace');
|
|
|
|
if (buildingSelect.value) {
|
|
const opt = buildingSelect.selectedOptions[0];
|
|
parts.push(opt.textContent.trim());
|
|
}
|
|
if (storeySelect.value) {
|
|
const opt = storeySelect.selectedOptions[0];
|
|
parts.push(opt.textContent.trim());
|
|
}
|
|
if (spaceSelect.value) {
|
|
const opt = spaceSelect.selectedOptions[0];
|
|
parts.push(opt.textContent.trim());
|
|
}
|
|
|
|
pathText.textContent = parts.join(' > ');
|
|
pathDiv.style.display = 'block';
|
|
}
|
|
|
|
// PropertySets generieren
|
|
function generatePropertySets() {
|
|
const container = document.getElementById('propertySetsContainer');
|
|
container.innerHTML = '';
|
|
|
|
if (!strukturData || !strukturData.PropertySets) {
|
|
document.getElementById('propertySetsSection').style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
strukturData.PropertySets.forEach(pset => {
|
|
const group = document.createElement('div');
|
|
group.className = 'pset-group';
|
|
group.innerHTML = `<h4>${pset.Label}</h4>`;
|
|
|
|
pset.Properties.forEach(prop => {
|
|
const propDiv = document.createElement('div');
|
|
propDiv.className = 'pset-property';
|
|
|
|
let inputHtml = '';
|
|
if (prop.Type === 'select' && prop.Options) {
|
|
inputHtml = `<select id="pset_${pset.Name}_${prop.Name}">
|
|
<option value="">-- Wahlen --</option>
|
|
${prop.Options.map(o => `<option value="${o}">${o}</option>`).join('')}
|
|
</select>`;
|
|
} else {
|
|
inputHtml = `<input type="text" id="pset_${pset.Name}_${prop.Name}" placeholder="${prop.Label}">`;
|
|
}
|
|
|
|
propDiv.innerHTML = `
|
|
<label>${prop.Label}</label>
|
|
${inputHtml}
|
|
`;
|
|
group.appendChild(propDiv);
|
|
});
|
|
|
|
container.appendChild(group);
|
|
});
|
|
|
|
document.getElementById('propertySetsSection').style.display = 'block';
|
|
}
|
|
|
|
// PropertySet-Werte sammeln
|
|
function collectPropertyValues() {
|
|
const values = {};
|
|
if (!strukturData || !strukturData.PropertySets) return values;
|
|
|
|
strukturData.PropertySets.forEach(pset => {
|
|
pset.Properties.forEach(prop => {
|
|
const input = document.getElementById(`pset_${pset.Name}_${prop.Name}`);
|
|
if (input && input.value) {
|
|
values[`${pset.Name}.${prop.Name}`] = input.value;
|
|
}
|
|
});
|
|
});
|
|
|
|
return values;
|
|
}
|
|
|
|
// Kamera offnen
|
|
function openCamera() {
|
|
document.getElementById('fileInput').click();
|
|
}
|
|
|
|
// Datei ausgewahlt
|
|
function onFileSelected(event) {
|
|
const file = event.target.files[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
capturedImageData = e.target.result;
|
|
|
|
// Vorschau anzeigen
|
|
const img = document.getElementById('previewImage');
|
|
img.src = capturedImageData;
|
|
img.style.display = 'block';
|
|
|
|
// Buttons umschalten
|
|
document.getElementById('btnCapture').style.display = 'none';
|
|
document.getElementById('previewButtons').style.display = 'flex';
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
|
|
// Aufnahme zurucksetzen
|
|
function resetCapture() {
|
|
capturedImageData = null;
|
|
document.getElementById('previewImage').style.display = 'none';
|
|
document.getElementById('previewImage').src = '';
|
|
document.getElementById('btnCapture').style.display = 'block';
|
|
document.getElementById('previewButtons').style.display = 'none';
|
|
document.getElementById('fileInput').value = '';
|
|
}
|
|
|
|
// Foto hochladen
|
|
async function uploadPhoto() {
|
|
if (!capturedImageData) {
|
|
showStatus('Bitte erst ein Foto aufnehmen', 'error');
|
|
return;
|
|
}
|
|
|
|
showLoading(true);
|
|
try {
|
|
// Upload-Daten zusammenstellen
|
|
const timestamp = Date.now().toString(16);
|
|
const fileName = `${sessionId}_${timestamp}.json`;
|
|
|
|
// Pfad bauen
|
|
const pathParts = [];
|
|
const buildingSelect = document.getElementById('selectBuilding');
|
|
const storeySelect = document.getElementById('selectStorey');
|
|
const spaceSelect = document.getElementById('selectSpace');
|
|
|
|
if (buildingSelect.value) pathParts.push(buildingSelect.selectedOptions[0].textContent.trim());
|
|
if (storeySelect.value) pathParts.push(storeySelect.selectedOptions[0].textContent.trim());
|
|
if (spaceSelect.value) pathParts.push(spaceSelect.selectedOptions[0].textContent.trim());
|
|
|
|
const uploadData = {
|
|
Timestamp: new Date().toISOString(),
|
|
Filename: `foto_${Date.now()}.jpg`,
|
|
Description: document.getElementById('description').value,
|
|
Base64: capturedImageData,
|
|
Size: capturedImageData.length,
|
|
Type: 'image/jpeg',
|
|
ElementGlobalId: selectedElement?.GlobalId || null,
|
|
ElementPath: pathParts.join(' > '),
|
|
Properties: collectPropertyValues()
|
|
};
|
|
|
|
// Per WebDAV PUT hochladen
|
|
const response = await fetch(`${DATA_URL}/${fileName}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(uploadData)
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Upload fehlgeschlagen: ${response.status}`);
|
|
}
|
|
|
|
// Erfolg
|
|
uploadCount++;
|
|
document.getElementById('uploadCount').textContent = uploadCount;
|
|
showStatus('Foto erfolgreich hochgeladen!', 'success');
|
|
|
|
// Zurucksetzen
|
|
resetCapture();
|
|
document.getElementById('description').value = '';
|
|
|
|
} catch (error) {
|
|
console.error('Upload-Fehler:', error);
|
|
showStatus('Upload fehlgeschlagen: ' + error.message, 'error');
|
|
} finally {
|
|
showLoading(false);
|
|
}
|
|
}
|
|
|
|
// Status-Meldung anzeigen
|
|
function showStatus(message, type) {
|
|
const statusDiv = document.getElementById('statusMessage');
|
|
statusDiv.textContent = message;
|
|
statusDiv.className = `status ${type}`;
|
|
statusDiv.style.display = 'block';
|
|
|
|
// Nach 5 Sekunden ausblenden
|
|
setTimeout(() => {
|
|
statusDiv.style.display = 'none';
|
|
}, 5000);
|
|
}
|
|
|
|
// Loading-Overlay
|
|
function showLoading(show) {
|
|
document.getElementById('loadingOverlay').classList.toggle('active', show);
|
|
}
|
|
</script>
|
|
|
|
|
|
<footer style="text-align:center;padding:1rem;margin-top:2rem;border-top:1px solid #e5e7eb;font-size:0.85rem;color:#6b7280;">
|
|
<a href="#" onclick="openImpressum();return false;" style="color:#6b7280;text-decoration:none;">Impressum</a>
|
|
<span style="color:#d1d5db;margin:0 0.5rem;">|</span>
|
|
<a href="#" onclick="openDatenschutz();return false;" style="color:#6b7280;text-decoration:none;">Datenschutz</a>
|
|
</footer>
|
|
|
|
|
|
<!-- IMPRESSUM MODAL -->
|
|
<div class="legal-modal" id="impressumModal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:9999;align-items:center;justify-content:center;">
|
|
<div style="background:white;width:90%;max-width:900px;height:90vh;border-radius:12px;margin:20px;overflow:hidden;display:flex;flex-direction:column;">
|
|
<div style="padding:0.75rem 1.5rem;border-bottom:1px solid #e5e7eb;display:flex;justify-content:space-between;align-items:center;flex-shrink:0;">
|
|
<h2 style="margin:0;font-size:1.25rem;color:#1f2937;">Impressum</h2>
|
|
<button onclick="closeImpressum()" style="background:none;border:none;font-size:1.5rem;cursor:pointer;color:#6b7280;line-height:1;">×</button>
|
|
</div>
|
|
<iframe src="/legal/impressum.html" style="flex:1;width:100%;border:none;"></iframe>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DATENSCHUTZ MODAL -->
|
|
<div class="legal-modal" id="datenschutzModal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:9999;align-items:center;justify-content:center;">
|
|
<div style="background:white;width:90%;max-width:900px;height:90vh;border-radius:12px;margin:20px;overflow:hidden;display:flex;flex-direction:column;">
|
|
<div style="padding:0.75rem 1.5rem;border-bottom:1px solid #e5e7eb;display:flex;justify-content:space-between;align-items:center;flex-shrink:0;">
|
|
<h2 style="margin:0;font-size:1.25rem;color:#1f2937;">Datenschutz</h2>
|
|
<button onclick="closeDatenschutz()" style="background:none;border:none;font-size:1.5rem;cursor:pointer;color:#6b7280;line-height:1;">×</button>
|
|
</div>
|
|
<iframe src="/legal/datenschutz.html" style="flex:1;width:100%;border:none;"></iframe>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function openImpressum(){document.getElementById("impressumModal").style.display="flex";}
|
|
function closeImpressum(){document.getElementById("impressumModal").style.display="none";}
|
|
function openDatenschutz(){document.getElementById("datenschutzModal").style.display="flex";}
|
|
function closeDatenschutz(){document.getElementById("datenschutzModal").style.display="none";}
|
|
document.addEventListener("keydown",function(e){if(e.key==="Escape"){closeImpressum();closeDatenschutz();}});
|
|
["impressumModal","datenschutzModal"].forEach(function(id){
|
|
var el=document.getElementById(id);
|
|
if(el)el.addEventListener("click",function(e){if(e.target===this)this.style.display="none";});
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|