Spaces:
Sleeping
Sleeping
File size: 4,826 Bytes
70d9e6c bec7397 70d9e6c bec7397 79b0691 bec7397 70d9e6c bec7397 79b0691 bec7397 79b0691 70d9e6c bec7397 70d9e6c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /** Standalone report page at /dda/reports/{runId} (FR-05). */
function parseReportRunId() {
const m = window.location.pathname.match(/\/dda\/reports\/(\d+)/);
return m ? parseInt(m[1], 10) : null;
}
function showReportError(msg) {
const el = document.getElementById('report-error');
if (!el) return;
el.textContent = msg;
el.classList.remove('hidden');
}
function formatCoord(v) {
if (v == null || v === '') return '—';
const n = Number(v);
return Number.isFinite(n) ? n.toFixed(5) : '—';
}
function regionLatLng(r) {
const ll = r.latLng || {};
const lat = r.latitude ?? ll.lat;
const lng = r.longitude ?? ll.lng;
return { lat, lng };
}
async function loadReportPage() {
const runId = parseReportRunId();
const loading = document.getElementById('report-loading');
const content = document.getElementById('report-content');
if (!runId) {
if (loading) loading.innerHTML = '<p class="dim">Invalid report URL.</p>';
return;
}
try {
const data = await ddaApi('GET', `/api/dda/reports/${runId}`);
if (loading) loading.classList.add('hidden');
if (content) content.classList.remove('hidden');
document.getElementById('report-title').textContent = data.title || `Run #${runId}`;
const loc = [data.village, data.zone].filter(Boolean).join(', ') || '—';
document.getElementById('report-meta').textContent =
`${data.method || '—'} · ${loc} · ${data.createdAt || ''}`;
const stats = data.statistics || {};
document.getElementById('report-stats').innerHTML = `
<div class="dda-stat"><span class="label">Change</span><span class="value">${(stats.changePercentage ?? 0).toFixed(2)}%</span></div>
<div class="dda-stat"><span class="label">Changed px</span><span class="value">${(stats.changedPixels ?? 0).toLocaleString()}</span></div>
<div class="dda-stat"><span class="label">Regions</span><span class="value">${data.regionsCount ?? (data.regions || []).length}</span></div>`;
const overlay = document.getElementById('report-overlay');
if (overlay) {
if (data.overlayBase64Png) {
overlay.src = `data:image/png;base64,${data.overlayBase64Png}`;
} else if (data.overlayUrl) {
overlay.src = data.overlayUrl;
} else {
overlay.alt = 'No overlay available';
}
}
const tbody = document.getElementById('report-regions-body');
const regions = data.regions || [];
if (tbody) {
tbody.innerHTML = regions.length
? regions.map((r) => {
const { lat, lng } = regionLatLng(r);
const hasCoords = Number.isFinite(Number(lat)) && Number.isFinite(Number(lng));
const mapsUrl = hasCoords
? `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`
: null;
return `
<tr>
<td>${r.id ?? ''}</td>
<td>${r.ddaChangeType || r.objectType || '—'}</td>
<td>${r.internalObjectType || r.objectType || '—'}</td>
<td>${((r.confidence ?? 0) * 100).toFixed(0)}%</td>
<td>${(r.area ?? 0).toLocaleString()}</td>
<td>${formatCoord(lat)}</td>
<td>${formatCoord(lng)}</td>
<td>${mapsUrl ? `<a class="btn btn-secondary btn-sm" href="${mapsUrl}" target="_blank" rel="noopener">Map</a>` : '—'}</td>
</tr>`;
}).join('')
: '<tr><td colspan="8" class="dim">No regions detected.</td></tr>';
}
const pdfBtn = document.getElementById('report-pdf-btn');
if (pdfBtn) {
pdfBtn.disabled = false;
pdfBtn.onclick = () => { window.location.href = `/api/dda/reports/${runId}/pdf`; };
}
const viewBtn = document.getElementById('report-view-btn');
if (viewBtn) {
viewBtn.disabled = false;
viewBtn.onclick = () => {
try { sessionStorage.setItem('dda_open_run', String(runId)); } catch (_) {}
window.location.href = '/?tab=reports';
};
}
window._reportPageData = data;
} catch (err) {
if (loading) loading.classList.add('hidden');
showReportError(err.message || 'Could not load report.');
}
}
document.getElementById('report-email-btn')?.addEventListener('click', async () => {
const runId = parseReportRunId();
const input = document.getElementById('report-email');
const msg = document.getElementById('report-email-msg');
const email = (input?.value || '').trim();
if (!email) {
if (msg) msg.textContent = 'Enter an email address.';
return;
}
try {
const res = await ddaApi('POST', `/api/dda/reports/${runId}/notify`, {
body: JSON.stringify({ email }),
});
if (msg) msg.textContent = res.message || 'Sent.';
} catch (err) {
if (msg) msg.textContent = err.message || 'Send failed.';
}
});
loadReportPage();
|