Spaces:
Running
Running
Guilherme Silberfarb Costa commited on
Commit ·
22106af
1
Parent(s): 5cc74bd
correcao no fluxo de exclusao/inclusao de coordenadas
Browse files
backend/app/api/elaboracao.py
CHANGED
|
@@ -170,6 +170,12 @@ def geocodificar_reiniciar(payload: SessionPayload) -> dict[str, Any]:
|
|
| 170 |
return elaboracao_service.reiniciar_geocodificacao(session)
|
| 171 |
|
| 172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
@router.post("/apply-selection")
|
| 174 |
def apply_selection(payload: ApplySelectionPayload) -> dict[str, Any]:
|
| 175 |
session = session_store.get(payload.session_id)
|
|
|
|
| 170 |
return elaboracao_service.reiniciar_geocodificacao(session)
|
| 171 |
|
| 172 |
|
| 173 |
+
@router.post("/geocodificar-excluir-coords")
|
| 174 |
+
def geocodificar_excluir_coords(payload: SessionPayload) -> dict[str, Any]:
|
| 175 |
+
session = session_store.get(payload.session_id)
|
| 176 |
+
return elaboracao_service.excluir_coordenadas_para_geocodificacao(session)
|
| 177 |
+
|
| 178 |
+
|
| 179 |
@router.post("/apply-selection")
|
| 180 |
def apply_selection(payload: ApplySelectionPayload) -> dict[str, Any]:
|
| 181 |
session = session_store.get(payload.session_id)
|
backend/app/services/elaboracao_service.py
CHANGED
|
@@ -364,6 +364,25 @@ def _build_coords_payload(df: pd.DataFrame, tem_coords: bool) -> dict[str, Any]:
|
|
| 364 |
}
|
| 365 |
|
| 366 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
def _set_dataframe_base(
|
| 368 |
session: SessionState,
|
| 369 |
df: pd.DataFrame,
|
|
@@ -1387,6 +1406,33 @@ def reiniciar_geocodificacao(session: SessionState) -> dict[str, Any]:
|
|
| 1387 |
}
|
| 1388 |
|
| 1389 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1390 |
def aplicar_correcoes_geocodificacao(
|
| 1391 |
session: SessionState,
|
| 1392 |
correcoes: list[dict[str, Any]],
|
|
|
|
| 364 |
}
|
| 365 |
|
| 366 |
|
| 367 |
+
def _remover_colunas_coordenadas(df: pd.DataFrame) -> tuple[pd.DataFrame, list[str]]:
|
| 368 |
+
"""Remove pares de colunas detectadas como coordenadas até não restar nenhum par válido."""
|
| 369 |
+
df_saida = df.copy()
|
| 370 |
+
removidas: list[str] = []
|
| 371 |
+
max_iter = max(1, len(df_saida.columns))
|
| 372 |
+
|
| 373 |
+
for _ in range(max_iter):
|
| 374 |
+
tem_coords, col_lat, col_lon = geocodificacao.verificar_coords(df_saida)
|
| 375 |
+
if not tem_coords or not col_lat or not col_lon:
|
| 376 |
+
break
|
| 377 |
+
|
| 378 |
+
for coluna in (str(col_lat), str(col_lon)):
|
| 379 |
+
if coluna in df_saida.columns:
|
| 380 |
+
removidas.append(coluna)
|
| 381 |
+
df_saida = df_saida.drop(columns=[col_lat, col_lon], errors="ignore")
|
| 382 |
+
|
| 383 |
+
return df_saida, list(dict.fromkeys(removidas))
|
| 384 |
+
|
| 385 |
+
|
| 386 |
def _set_dataframe_base(
|
| 387 |
session: SessionState,
|
| 388 |
df: pd.DataFrame,
|
|
|
|
| 1406 |
}
|
| 1407 |
|
| 1408 |
|
| 1409 |
+
def excluir_coordenadas_para_geocodificacao(session: SessionState) -> dict[str, Any]:
|
| 1410 |
+
if session.df_original is None:
|
| 1411 |
+
raise HTTPException(status_code=400, detail="Carregue dados primeiro")
|
| 1412 |
+
|
| 1413 |
+
df_sem_coords, removidas = _remover_colunas_coordenadas(session.df_original)
|
| 1414 |
+
if not removidas:
|
| 1415 |
+
raise HTTPException(status_code=400, detail="Nao ha coordenadas detectadas para excluir")
|
| 1416 |
+
|
| 1417 |
+
session.df_original = df_sem_coords.copy()
|
| 1418 |
+
session.df_filtrado = df_sem_coords.drop(index=session.outliers_anteriores, errors="ignore")
|
| 1419 |
+
session.df_geo_origem = df_sem_coords.copy()
|
| 1420 |
+
session.geo_falhas_df = None
|
| 1421 |
+
session.geo_col_cdlog = None
|
| 1422 |
+
session.geo_col_num = None
|
| 1423 |
+
session.mapa_habilitado = False
|
| 1424 |
+
|
| 1425 |
+
return {
|
| 1426 |
+
"status": "Coordenadas removidas. Configure a geocodificacao para gerar novas coordenadas.",
|
| 1427 |
+
"status_html": "",
|
| 1428 |
+
"falhas_html": "",
|
| 1429 |
+
"falhas_para_correcao": dataframe_to_payload(pd.DataFrame(), decimals=None),
|
| 1430 |
+
"mapa_html": _render_mapa_if_enabled(session, session.df_filtrado),
|
| 1431 |
+
"dados": dataframe_to_payload(session.df_filtrado, decimals=4),
|
| 1432 |
+
"coords": _build_coords_payload(session.df_original, False),
|
| 1433 |
+
}
|
| 1434 |
+
|
| 1435 |
+
|
| 1436 |
def aplicar_correcoes_geocodificacao(
|
| 1437 |
session: SessionState,
|
| 1438 |
correcoes: list[dict[str, Any]],
|
frontend/src/api.js
CHANGED
|
@@ -89,6 +89,7 @@ export const api = {
|
|
| 89 |
geocodificar: (sessionId, colCdlog, colNum, auto200) => postJson('/api/elaboracao/geocodificar', { session_id: sessionId, col_cdlog: colCdlog, col_num: colNum, auto_200: auto200 }),
|
| 90 |
geocodificarCorrecoes: (sessionId, correcoes, auto200) => postJson('/api/elaboracao/geocodificar-correcoes', { session_id: sessionId, correcoes, auto_200: auto200 }),
|
| 91 |
geocodificarReiniciar: (sessionId) => postJson('/api/elaboracao/geocodificar-reiniciar', { session_id: sessionId }),
|
|
|
|
| 92 |
|
| 93 |
applySelection(payload) {
|
| 94 |
return postJson('/api/elaboracao/apply-selection', payload)
|
|
|
|
| 89 |
geocodificar: (sessionId, colCdlog, colNum, auto200) => postJson('/api/elaboracao/geocodificar', { session_id: sessionId, col_cdlog: colCdlog, col_num: colNum, auto_200: auto200 }),
|
| 90 |
geocodificarCorrecoes: (sessionId, correcoes, auto200) => postJson('/api/elaboracao/geocodificar-correcoes', { session_id: sessionId, correcoes, auto_200: auto200 }),
|
| 91 |
geocodificarReiniciar: (sessionId) => postJson('/api/elaboracao/geocodificar-reiniciar', { session_id: sessionId }),
|
| 92 |
+
geocodificarExcluirCoords: (sessionId) => postJson('/api/elaboracao/geocodificar-excluir-coords', { session_id: sessionId }),
|
| 93 |
|
| 94 |
applySelection(payload) {
|
| 95 |
return postJson('/api/elaboracao/apply-selection', payload)
|
frontend/src/components/ElaboracaoTab.jsx
CHANGED
|
@@ -562,6 +562,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 562 |
const [manualMapError, setManualMapError] = useState('')
|
| 563 |
const [geoProcessError, setGeoProcessError] = useState('')
|
| 564 |
const [coordsMode, setCoordsMode] = useState('menu')
|
|
|
|
| 565 |
|
| 566 |
const [colunasNumericas, setColunasNumericas] = useState([])
|
| 567 |
const [colunaY, setColunaY] = useState('')
|
|
@@ -883,6 +884,12 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 883 |
}
|
| 884 |
}, [coordsInfo])
|
| 885 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 886 |
useEffect(() => {
|
| 887 |
if (marcarTodasXRef.current) {
|
| 888 |
marcarTodasXRef.current.indeterminate = algumaXMarcada && !todasXMarcadas
|
|
@@ -1450,6 +1457,30 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 1450 |
setManualMapError('')
|
| 1451 |
setGeoProcessError('')
|
| 1452 |
setCoordsMode(resp.coords?.tem_coords ? 'menu' : 'geocodificar')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1453 |
})
|
| 1454 |
}
|
| 1455 |
|
|
@@ -2249,12 +2280,50 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 2249 |
</>
|
| 2250 |
) : (
|
| 2251 |
<div className="subpanel coords-section-group">
|
| 2252 |
-
|
| 2253 |
-
|
| 2254 |
-
|
| 2255 |
-
|
| 2256 |
-
|
| 2257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2258 |
</div>
|
| 2259 |
)}
|
| 2260 |
</div>
|
|
|
|
| 562 |
const [manualMapError, setManualMapError] = useState('')
|
| 563 |
const [geoProcessError, setGeoProcessError] = useState('')
|
| 564 |
const [coordsMode, setCoordsMode] = useState('menu')
|
| 565 |
+
const [confirmarExclusaoCoords, setConfirmarExclusaoCoords] = useState(false)
|
| 566 |
|
| 567 |
const [colunasNumericas, setColunasNumericas] = useState([])
|
| 568 |
const [colunaY, setColunaY] = useState('')
|
|
|
|
| 884 |
}
|
| 885 |
}, [coordsInfo])
|
| 886 |
|
| 887 |
+
useEffect(() => {
|
| 888 |
+
if (!coordsInfo?.tem_coords || coordsMode !== 'menu') {
|
| 889 |
+
setConfirmarExclusaoCoords(false)
|
| 890 |
+
}
|
| 891 |
+
}, [coordsInfo, coordsMode])
|
| 892 |
+
|
| 893 |
useEffect(() => {
|
| 894 |
if (marcarTodasXRef.current) {
|
| 895 |
marcarTodasXRef.current.indeterminate = algumaXMarcada && !todasXMarcadas
|
|
|
|
| 1457 |
setManualMapError('')
|
| 1458 |
setGeoProcessError('')
|
| 1459 |
setCoordsMode(resp.coords?.tem_coords ? 'menu' : 'geocodificar')
|
| 1460 |
+
setConfirmarExclusaoCoords(false)
|
| 1461 |
+
})
|
| 1462 |
+
}
|
| 1463 |
+
|
| 1464 |
+
async function onExcluirCoordenadasParaGeocodificar() {
|
| 1465 |
+
if (!sessionId) return
|
| 1466 |
+
await withBusy(async () => {
|
| 1467 |
+
const resp = await api.geocodificarExcluirCoords(sessionId)
|
| 1468 |
+
setStatus(resp.status || '')
|
| 1469 |
+
setGeoStatusHtml(resp.status_html || '')
|
| 1470 |
+
setGeoFalhasHtml(resp.falhas_html || '')
|
| 1471 |
+
setGeoCorrecoes(parseCorrecoes(resp.falhas_para_correcao))
|
| 1472 |
+
setMapaHtml(resp.mapa_html || '')
|
| 1473 |
+
setDados(resp.dados || null)
|
| 1474 |
+
setCoordsInfo(resp.coords || null)
|
| 1475 |
+
setManualLat(resp.coords?.colunas_disponiveis?.[0] || '')
|
| 1476 |
+
setManualLon(resp.coords?.colunas_disponiveis?.[1] || '')
|
| 1477 |
+
setGeoCdlog(escolherColunaCdlogPadrao(resp.coords || null))
|
| 1478 |
+
setGeoNum(resp.coords?.num_auto || '')
|
| 1479 |
+
setGeoAuto200(true)
|
| 1480 |
+
setManualMapError('')
|
| 1481 |
+
setGeoProcessError('')
|
| 1482 |
+
setCoordsMode('menu')
|
| 1483 |
+
setConfirmarExclusaoCoords(false)
|
| 1484 |
})
|
| 1485 |
}
|
| 1486 |
|
|
|
|
| 2280 |
</>
|
| 2281 |
) : (
|
| 2282 |
<div className="subpanel coords-section-group">
|
| 2283 |
+
{coordsMode === 'skipped' ? (
|
| 2284 |
+
<>
|
| 2285 |
+
<div className="section1-empty-hint">Você optou por prosseguir sem mapear coordenadas nesta etapa.</div>
|
| 2286 |
+
<div className="row coords-restart-row">
|
| 2287 |
+
<button
|
| 2288 |
+
type="button"
|
| 2289 |
+
onClick={() => {
|
| 2290 |
+
setManualMapError('')
|
| 2291 |
+
setGeoProcessError('')
|
| 2292 |
+
setCoordsMode('menu')
|
| 2293 |
+
}}
|
| 2294 |
+
disabled={loading}
|
| 2295 |
+
>
|
| 2296 |
+
Configurar coordenadas
|
| 2297 |
+
</button>
|
| 2298 |
+
</div>
|
| 2299 |
+
</>
|
| 2300 |
+
) : coordsInfo?.tem_coords ? (
|
| 2301 |
+
<>
|
| 2302 |
+
<div className="coords-ready-hint">Todos os dados já possuem suas coordenadas mapeadas.</div>
|
| 2303 |
+
<div className="row coords-restart-row">
|
| 2304 |
+
<button type="button" onClick={() => setConfirmarExclusaoCoords(true)} disabled={loading}>
|
| 2305 |
+
Excluir coordenadas e refazer geocodificação
|
| 2306 |
+
</button>
|
| 2307 |
+
</div>
|
| 2308 |
+
{confirmarExclusaoCoords ? (
|
| 2309 |
+
<div className="coords-confirm-delete">
|
| 2310 |
+
<div className="coords-confirm-delete-text">
|
| 2311 |
+
Confirma excluir as coordenadas atuais para iniciar uma nova geocodificação?
|
| 2312 |
+
</div>
|
| 2313 |
+
<div className="row compact coords-confirm-delete-actions">
|
| 2314 |
+
<button type="button" className="btn-confirm-delete" onClick={onExcluirCoordenadasParaGeocodificar} disabled={loading}>
|
| 2315 |
+
Confirmar exclusão
|
| 2316 |
+
</button>
|
| 2317 |
+
<button type="button" onClick={() => setConfirmarExclusaoCoords(false)} disabled={loading}>
|
| 2318 |
+
Cancelar
|
| 2319 |
+
</button>
|
| 2320 |
+
</div>
|
| 2321 |
+
</div>
|
| 2322 |
+
) : null}
|
| 2323 |
+
</>
|
| 2324 |
+
) : (
|
| 2325 |
+
<div className="section1-empty-hint">Etapa de coordenadas concluída.</div>
|
| 2326 |
+
)}
|
| 2327 |
</div>
|
| 2328 |
)}
|
| 2329 |
</div>
|
frontend/src/styles.css
CHANGED
|
@@ -1412,6 +1412,32 @@ button.btn-upload-select {
|
|
| 1412 |
font-size: 0.86rem;
|
| 1413 |
}
|
| 1414 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1415 |
.coords-choice-row {
|
| 1416 |
display: flex;
|
| 1417 |
flex-wrap: wrap;
|
|
@@ -2292,6 +2318,14 @@ button.btn-upload-select {
|
|
| 2292 |
--btn-shadow-strong: rgba(255, 140, 0, 0.28);
|
| 2293 |
}
|
| 2294 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2295 |
.outlier-actions-row button.btn-filtro-add {
|
| 2296 |
--btn-bg-start: #2f80cf;
|
| 2297 |
--btn-bg-end: #2368af;
|
|
|
|
| 1412 |
font-size: 0.86rem;
|
| 1413 |
}
|
| 1414 |
|
| 1415 |
+
.coords-ready-hint {
|
| 1416 |
+
color: #1f5e3a;
|
| 1417 |
+
font-size: 0.88rem;
|
| 1418 |
+
font-weight: 600;
|
| 1419 |
+
}
|
| 1420 |
+
|
| 1421 |
+
.coords-confirm-delete {
|
| 1422 |
+
margin-top: 10px;
|
| 1423 |
+
border: 1px solid #f0cf9f;
|
| 1424 |
+
background: #fffaf2;
|
| 1425 |
+
border-radius: 10px;
|
| 1426 |
+
padding: 10px 12px;
|
| 1427 |
+
display: grid;
|
| 1428 |
+
gap: 8px;
|
| 1429 |
+
}
|
| 1430 |
+
|
| 1431 |
+
.coords-confirm-delete-text {
|
| 1432 |
+
color: #7a4d00;
|
| 1433 |
+
font-size: 0.84rem;
|
| 1434 |
+
font-weight: 600;
|
| 1435 |
+
}
|
| 1436 |
+
|
| 1437 |
+
.coords-confirm-delete-actions {
|
| 1438 |
+
margin: 0;
|
| 1439 |
+
}
|
| 1440 |
+
|
| 1441 |
.coords-choice-row {
|
| 1442 |
display: flex;
|
| 1443 |
flex-wrap: wrap;
|
|
|
|
| 2318 |
--btn-shadow-strong: rgba(255, 140, 0, 0.28);
|
| 2319 |
}
|
| 2320 |
|
| 2321 |
+
.row button.btn-confirm-delete {
|
| 2322 |
+
--btn-bg-start: #d92d20;
|
| 2323 |
+
--btn-bg-end: #b42318;
|
| 2324 |
+
--btn-border: #912018;
|
| 2325 |
+
--btn-shadow-soft: rgba(217, 45, 32, 0.2);
|
| 2326 |
+
--btn-shadow-strong: rgba(180, 35, 24, 0.28);
|
| 2327 |
+
}
|
| 2328 |
+
|
| 2329 |
.outlier-actions-row button.btn-filtro-add {
|
| 2330 |
--btn-bg-start: #2f80cf;
|
| 2331 |
--btn-bg-end: #2368af;
|