Files
ap-capture/frontend/index.html
2026-01-26 04:57:20 -06:00

155 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AP Installation Capture</title>
<style>
body { font-family: sans-serif; padding: 1em; max-width: 700px; margin: auto; }
label { display: block; margin-top: 1em; }
input, button { width: 100%; padding: 0.5em; margin-top: 0.25em; }
button { width: auto; padding: 0.5em 1em; }
.row { display: flex; align-items: flex-end; gap: 0.5em; margin-top: 1em; }
.row input { flex: 1; }
.status { margin-top: 1em; font-weight: bold; }
.preview { margin-top: 0.25em; max-width: 100%; width: 500px; height: auto; border: 1px solid #ccc; }
</style>
</head>
<body>
<h1>AP Installation Capture</h1>
<form id="apForm">
<div class="row">
<label for="site_id">Site ID:</label>
<input type="text" id="site_id" name="site_id" pattern="\d+" required
autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false">
<button type="button" id="clearSite">Clear</button>
</div>
<label for="ap_location">AP Location (3 digits):</label>
<input type="text" id="ap_location" name="ap_location" pattern="\d{3}" required
autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false">
<label for="length">Cable Length (numeric):</label>
<input type="number" id="length" name="cable_length" step="0.01" required
autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false">
<label for="serial_number">Serial Number (XXXX-XXXX-XXXX):</label>
<input type="text" id="serial_number" name="serial_number" pattern="[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}" required
autocapitalize="characters" autocomplete="off" autocorrect="off" spellcheck="false">
<label for="continuity">Continuity Photo:</label>
<input type="file" id="continuity" name="photo_continuity" accept="image/*" required>
<img id="preview_continuity" class="preview">
<label for="length_photo">Length Check Photo:</label>
<input type="file" id="length_photo" name="photo_length" accept="image/*" required>
<img id="preview_length_photo" class="preview">
<label for="verification">Verification Photo:</label>
<input type="file" id="verification" name="photo_verification" accept="image/*" required>
<img id="preview_verification" class="preview">
<label for="ap_close">AP Close-up Photo:</label>
<input type="file" id="ap_close" name="photo_close" accept="image/*" required>
<img id="preview_ap_close" class="preview">
<label for="ap_far">AP Distant Photo:</label>
<input type="file" id="ap_far" name="photo_distance" accept="image/*" required>
<img id="preview_ap_far" class="preview">
<button type="submit">Submit</button>
</form>
<div class="status" id="status"></div>
<script>
// Keep Site ID persistent in sessionStorage
const siteInput = document.getElementById('site_id');
const storedSite = sessionStorage.getItem('site_id');
if(storedSite) siteInput.value = storedSite;
document.getElementById('clearSite').addEventListener('click', () => {
siteInput.value = '';
sessionStorage.removeItem('site_id');
});
// Preview function
function setupPreview(inputId, previewId) {
const input = document.getElementById(inputId);
const preview = document.getElementById(previewId);
input.addEventListener('change', () => {
if(input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = e => preview.src = e.target.result;
reader.readAsDataURL(input.files[0]);
} else {
preview.src = '';
}
});
}
setupPreview('continuity', 'preview_continuity');
setupPreview('length_photo', 'preview_length_photo');
setupPreview('verification', 'preview_verification');
setupPreview('ap_close', 'preview_ap_close');
setupPreview('ap_far', 'preview_ap_far');
// Form submission
document.getElementById('apForm').addEventListener('submit', async (e) => {
e.preventDefault();
const status = document.getElementById('status');
status.textContent = "Submitting...";
// Save site ID
sessionStorage.setItem('site_id', siteInput.value);
const formData = new FormData();
formData.append('site_id', siteInput.value);
formData.append('ap_location', document.getElementById('ap_location').value);
formData.append('cable_length', document.getElementById('length').value);
formData.append('serial_number', document.getElementById('serial_number').value);
formData.append('photo_continuity', document.getElementById('continuity').files[0]);
formData.append('photo_length', document.getElementById('length_photo').files[0]);
formData.append('photo_verification', document.getElementById('verification').files[0]);
formData.append('photo_close', document.getElementById('ap_close').files[0]);
formData.append('photo_distance', document.getElementById('ap_far').files[0]);
try {
const response = await fetch('/api/ap/submit', {
method: 'POST',
body: formData
});
if (!response.ok) {
const errorData = await response.json();
if (typeof errorData.detail === 'string') {
status.textContent = "Error: " + errorData.detail;
} else if (typeof errorData.detail === 'object') {
status.textContent = "Error: " + JSON.stringify(errorData.detail);
} else {
status.textContent = "Error: " + response.statusText;
}
} else {
const data = await response.json();
status.textContent = `Success! Site ${data.site_id}, AP ${data.ap_location} submitted.`;
// Optional: reset form except Site ID and previews
document.getElementById('ap_location').value = '';
document.getElementById('length').value = '';
document.getElementById('serial_number').value = '';
['continuity','length_photo','verification','ap_close','ap_far'].forEach(id=>{
document.getElementById(id).value='';
});
['preview_continuity','preview_length_photo','preview_verification','preview_ap_close','preview_ap_far'].forEach(pid=>{
document.getElementById(pid).src='';
});
}
} catch (err) {
status.textContent = "Network error: " + err;
}
});
</script>
</body>
</html>