Add Gamma SBAS production workflow

This commit is contained in:
2026-05-21 04:53:39 +08:00
parent 9000feeee8
commit cc22b9ac2d
46 changed files with 11386 additions and 332 deletions
+97 -3
View File
@@ -282,6 +282,8 @@ function App() {
const aoeLayerRef = useRef(null);
const waterSceneLayersRef = useRef({});
const floodEventLayersRef = useRef({}); // { eventId: { pre, post, classified } }
const floodPairPreviewLayerRef = useRef(null);
const floodVectorLayersRef = useRef({});
const mapRegionLayerRef = useRef(null);
const prevLicenseOkRef = useRef(false);
const initializeAppDataRef = useRef(null);
@@ -327,6 +329,7 @@ function App() {
pairLayersRef: pairLayersRef.current,
aoeLayerRef: aoeLayerRef.current,
floodEventLayersRef: floodEventLayersRef.current,
floodVectorLayersRef: floodVectorLayersRef.current,
}), []);
const mapExport = useMapExport({ mapRef, getVisibleLayerRefs, addLog, language });
@@ -1468,8 +1471,11 @@ function App() {
const handleWaterSceneOnMap = (scene) => {
if (!mapRef.current || !scene.coverage_polygon) return;
if (waterSceneLayersRef.current[scene.id]) {
waterSceneLayersRef.current[scene.id].remove();
const layerKey = scene.radar_data_id ? `scene_${scene.id}` : `radar_${scene.id}`;
if (waterSceneLayersRef.current[layerKey]) {
waterSceneLayersRef.current[layerKey].remove();
delete waterSceneLayersRef.current[layerKey];
return false;
}
const latLngs = scene.coverage_polygon.map(p => [p[1], p[0]]);
const polygon = L.polygon(latLngs, {
@@ -1484,10 +1490,35 @@ function App() {
`${scene.satellite || ''} · ${scene.imaging_date || ''}<br>` +
`<span style="color:#888;font-size:11px">${(scene.geo_path || '').split(/[\\/]/).pop()}</span>`
);
waterSceneLayersRef.current[scene.id] = polygon;
waterSceneLayersRef.current[layerKey] = polygon;
polygon.addTo(mapRef.current);
mapRef.current.flyToBounds(L.latLngBounds(latLngs), { padding: [50, 50], maxZoom: 10 });
polygon.openPopup();
return true;
};
const handleFloodSourcePreviewOnMap = (item) => {
if (!mapRef.current || !item) return;
const enriched = {
...item,
displayName: item.displayName || item.file_path?.split(/[\\/]/).pop() || `${item.satellite || 'SAR'} #${item.id}`,
previewCacheKey: item.previewCacheKey || item.preview_cache_updated_at || `${Date.now()}-${item.id}`,
};
if (radarPreviewLayersRef.current[enriched.id]) {
updateRadarPreviewVisibility(enriched, false);
return false;
}
updateRadarPreviewVisibility(enriched, true);
if (
enriched.min_lat != null && enriched.max_lat != null
&& enriched.min_lon != null && enriched.max_lon != null
) {
mapRef.current.flyToBounds(
L.latLngBounds([[enriched.min_lat, enriched.min_lon], [enriched.max_lat, enriched.max_lon]]),
{ padding: [50, 50], maxZoom: 10 },
);
}
return true;
};
// 洪涝事件三图层叠加(灾前/灾后/分类结果),每层可独立开关
@@ -1534,6 +1565,66 @@ function App() {
else layers[key].remove();
};
const handleFloodPairPreviewOnMap = (pair) => {
if (!mapRef.current || !pair?.pre?.coverage_polygon || !pair?.post?.coverage_polygon) return;
if (floodPairPreviewLayerRef.current) {
floodPairPreviewLayerRef.current.remove();
floodPairPreviewLayerRef.current = null;
}
const makePolygon = (scene, color, label) => {
const latLngs = scene.coverage_polygon.map(p => [p[1], p[0]]);
const polygon = L.polygon(latLngs, {
color,
weight: 2,
fillColor: color,
fillOpacity: 0.14,
});
polygon.bindPopup(
`<strong>${escapeHtml(label)}</strong><br>` +
`场景 #${escapeHtml(scene.id)} · ${escapeHtml(scene.satellite || '')}<br>` +
`${escapeHtml(formatYmd(scene.imaging_date, language))} · ${escapeHtml(scene.polarization || '')}`
);
return polygon;
};
const prePolygon = makePolygon(pair.pre, '#2563eb', '灾前覆盖');
const postPolygon = makePolygon(pair.post, '#16a34a', '灾后覆盖');
const group = L.featureGroup([prePolygon, postPolygon]);
floodPairPreviewLayerRef.current = group;
group.addTo(mapRef.current);
mapRef.current.flyToBounds(group.getBounds(), { padding: [50, 50], maxZoom: 10 });
};
const handleFloodVectorOnMap = (impact) => {
if (!mapRef.current || !impact?.flood_vector_geojson) return;
const layerId = impact.overlay_id || impact.detection_id || 'current';
const existing = floodVectorLayersRef.current[layerId];
if (existing) existing.remove();
const layer = L.geoJSON(impact.flood_vector_geojson, {
style: {
color: '#dc2626',
weight: 2,
fillColor: '#ef4444',
fillOpacity: 0.26,
},
onEachFeature: (feature, featureLayer) => {
const props = feature?.properties || {};
featureLayer.bindPopup(
`<strong>洪涝矢量</strong><br>` +
`Overlay #${escapeHtml(layerId)}<br>` +
`${escapeHtml(props.name || props.class || '')}`
);
},
});
floodVectorLayersRef.current[layerId] = layer;
layer.addTo(mapRef.current);
const bounds = layer.getBounds();
if (bounds.isValid()) {
mapRef.current.flyToBounds(bounds, { padding: [50, 50], maxZoom: 12 });
}
};
const visualizePair = useCallback((pair) => {
const masterLatLngs = pair.master.coverage_polygon.map(p => [p[1], p[0]]);
const slaveLatLngs = pair.slave.coverage_polygon.map(p => [p[1], p[0]]);
@@ -1644,11 +1735,14 @@ function App() {
};
const floodPanel = {
onShowSourceSceneOnMap: handleWaterSceneOnMap,
onShowSourcePreviewOnMap: handleFloodSourcePreviewOnMap,
onShowReadyProductOnMap: handleWaterSceneOnMap,
onShowOnMap: handleWaterSceneOnMap,
onShowFloodOnMap: handleFloodEventOnMap,
onShowFloodRunOnMap: handleFloodEventOnMap,
onToggleFloodLayer: toggleFloodEventLayer,
onShowFloodPairOnMap: handleFloodPairPreviewOnMap,
onShowFloodVectorOnMap: handleFloodVectorOnMap,
};
const dinsarPanel = {
dinsarCurrentPage,