Spaces:
Running
Running
Guilherme Silberfarb Costa commited on
Commit ·
5cc74bd
1
Parent(s): 949bf68
melhora no registro de variaveis selecionadas
Browse files
backend/app/core/pesquisa/pesquisa_admin_config.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"area": [
|
| 3 |
+
"var:ACONST",
|
| 4 |
+
"var:ALOC",
|
| 5 |
+
"var:APRIV",
|
| 6 |
+
"var:APRIVEQ",
|
| 7 |
+
"var:ATTOTAL"
|
| 8 |
+
],
|
| 9 |
+
"aval_area": [
|
| 10 |
+
"var:ACONST",
|
| 11 |
+
"var:ALOC",
|
| 12 |
+
"var:APRIV",
|
| 13 |
+
"var:APRIVEQ",
|
| 14 |
+
"var:ATTOTAL"
|
| 15 |
+
],
|
| 16 |
+
"aval_area_privativa": [
|
| 17 |
+
"var:APRIV",
|
| 18 |
+
"var:APRIVEQ"
|
| 19 |
+
],
|
| 20 |
+
"aval_area_total": [
|
| 21 |
+
"var:ATTOTAL"
|
| 22 |
+
],
|
| 23 |
+
"aval_bairro": [
|
| 24 |
+
"col:NME BAI"
|
| 25 |
+
],
|
| 26 |
+
"aval_data": [],
|
| 27 |
+
"aval_finalidade": [
|
| 28 |
+
"col:FINALIDADE",
|
| 29 |
+
"col:NME IMO-FINAL"
|
| 30 |
+
],
|
| 31 |
+
"aval_rh": [
|
| 32 |
+
"var:RH"
|
| 33 |
+
],
|
| 34 |
+
"aval_valor_total": [
|
| 35 |
+
"var:VLOC",
|
| 36 |
+
"var:VTOTAL"
|
| 37 |
+
],
|
| 38 |
+
"aval_valor_unitario": [
|
| 39 |
+
"var:VUACONST",
|
| 40 |
+
"var:VUNIPRIV",
|
| 41 |
+
"var:VUNIT"
|
| 42 |
+
],
|
| 43 |
+
"bairros": [
|
| 44 |
+
"col:BAIRRO",
|
| 45 |
+
"col:Bairro",
|
| 46 |
+
"col:NME BAI"
|
| 47 |
+
],
|
| 48 |
+
"data": [
|
| 49 |
+
"meta:faixa_data"
|
| 50 |
+
],
|
| 51 |
+
"finalidade": [
|
| 52 |
+
"col:FINALIDADE",
|
| 53 |
+
"col:NME IMO-FINAL"
|
| 54 |
+
],
|
| 55 |
+
"rh": [
|
| 56 |
+
"var:RH"
|
| 57 |
+
]
|
| 58 |
+
}
|
frontend/src/components/ElaboracaoTab.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
| 2 |
import { api, downloadBlob } from '../api'
|
| 3 |
import Plotly from 'plotly.js-dist-min'
|
| 4 |
import DataTable from './DataTable'
|
|
@@ -593,6 +593,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 593 |
const [section8Open, setSection8Open] = useState(false)
|
| 594 |
const [section10ManualOpen, setSection10ManualOpen] = useState(false)
|
| 595 |
const [section11Open, setSection11Open] = useState(false)
|
|
|
|
| 596 |
|
| 597 |
const [fit, setFit] = useState(null)
|
| 598 |
const [tipoDispersao, setTipoDispersao] = useState('Variáveis Independentes Transformadas X Variável Dependente Transformada')
|
|
@@ -624,6 +625,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 624 |
const classificarXReqRef = useRef(0)
|
| 625 |
const deleteConfirmTimersRef = useRef({})
|
| 626 |
const uploadInputRef = useRef(null)
|
|
|
|
| 627 |
|
| 628 |
const mapaChoices = useMemo(() => ['Visualização Padrão', ...colunasNumericas], [colunasNumericas])
|
| 629 |
const colunasXDisponiveis = useMemo(
|
|
@@ -668,6 +670,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 668 |
[periodoDadosMercadoPreview],
|
| 669 |
)
|
| 670 |
const pendingWarningText = 'Há alterações em campos que ainda não foram aplicadas.'
|
|
|
|
| 671 |
const dataMercadoPendente = useMemo(
|
| 672 |
() => String(colunaDataMercado || '') !== String(colunaDataMercadoAplicada || ''),
|
| 673 |
[colunaDataMercado, colunaDataMercadoAplicada],
|
|
@@ -710,6 +713,34 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 710 |
() => Boolean(selection) && Boolean(section10ManualOpen) && manualTransformSnapshotAtual !== manualTransformAppliedSnapshot,
|
| 711 |
[selection, section10ManualOpen, manualTransformSnapshotAtual, manualTransformAppliedSnapshot],
|
| 712 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
const outlierFiltrosSnapshotAtual = useMemo(
|
| 714 |
() => buildFiltrosSnapshot(filtros),
|
| 715 |
[filtros],
|
|
@@ -793,6 +824,59 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 793 |
)
|
| 794 |
const baseCarregada = Boolean(dados)
|
| 795 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 796 |
useEffect(() => {
|
| 797 |
if (coordsInfo && !coordsInfo.tem_coords) {
|
| 798 |
setCoordsMode('menu')
|
|
@@ -962,6 +1046,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 962 |
setPeriodoDadosMercadoPreview(null)
|
| 963 |
setDataMercadoError('')
|
| 964 |
setSelection(null)
|
|
|
|
| 965 |
setFit(null)
|
| 966 |
setFiltros(defaultFiltros())
|
| 967 |
setOutliersTexto('')
|
|
@@ -998,6 +1083,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 998 |
|
| 999 |
function applySelectionResponse(resp) {
|
| 1000 |
setSelection(resp)
|
|
|
|
| 1001 |
setSection8Open(false)
|
| 1002 |
setSection10ManualOpen(false)
|
| 1003 |
setTransformacoesAplicadas(null)
|
|
@@ -1256,6 +1342,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 1256 |
setDicotomicas(proximasDicotomicas)
|
| 1257 |
setCodigoAlocado(proximoCodigoAlocado)
|
| 1258 |
setPercentuais(proximosPercentuais)
|
|
|
|
| 1259 |
setSelectionAppliedSnapshot(buildSelectionSnapshot({ coluna_y: proximaColunaY }))
|
| 1260 |
setSelection(null)
|
| 1261 |
setFit(null)
|
|
@@ -1395,6 +1482,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 1395 |
const resp = await api.applySelection(payload)
|
| 1396 |
applySelectionResponse(resp)
|
| 1397 |
setSelectionAppliedSnapshot(buildSelectionSnapshot(payload))
|
|
|
|
| 1398 |
setFit(null)
|
| 1399 |
setOutlierFiltrosAplicadosSnapshot(buildFiltrosSnapshot(defaultFiltros()))
|
| 1400 |
setOutlierTextosAplicadosSnapshot(buildOutlierTextSnapshot('', ''))
|
|
@@ -1532,6 +1620,7 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 1532 |
setOutliersAnteriores([])
|
| 1533 |
setIteracao(1)
|
| 1534 |
setSelection(null)
|
|
|
|
| 1535 |
setFit(null)
|
| 1536 |
setTransformacoesAplicadas(null)
|
| 1537 |
setOrigemTransformacoes(null)
|
|
@@ -2265,17 +2354,27 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 2265 |
</select>
|
| 2266 |
</div>
|
| 2267 |
<div className="row market-date-actions-row">
|
| 2268 |
-
<div className="resumo-outliers-box">
|
| 2269 |
Período identificado: {periodoDadosMercadoPreviewTexto}
|
| 2270 |
</div>
|
| 2271 |
-
<
|
| 2272 |
-
|
| 2273 |
-
|
| 2274 |
-
|
| 2275 |
-
|
| 2276 |
-
|
| 2277 |
-
|
| 2278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2279 |
</div>
|
| 2280 |
{dataMercadoError ? <div className="error-line inline-error">{dataMercadoError}</div> : null}
|
| 2281 |
</div>
|
|
@@ -2290,15 +2389,25 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 2290 |
<option key={col} value={col}>{col}</option>
|
| 2291 |
))}
|
| 2292 |
</select>
|
| 2293 |
-
|
| 2294 |
-
|
| 2295 |
-
|
| 2296 |
-
|
|
|
|
|
|
|
|
|
|
| 2297 |
>
|
| 2298 |
-
|
| 2299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2300 |
{dependentePendente ? <span className="pending-apply-note">{pendingWarningText}</span> : null}
|
| 2301 |
</div>
|
|
|
|
| 2302 |
</SectionBlock>
|
| 2303 |
|
| 2304 |
<SectionBlock step="6" title="Selecionar Variáveis Independentes" subtitle="Escolha regressoras e grupos de tipologia.">
|
|
@@ -2307,77 +2416,151 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 2307 |
Aplique a variável dependente na etapa anterior para liberar as opções de variáveis independentes.
|
| 2308 |
</div>
|
| 2309 |
) : null}
|
| 2310 |
-
|
| 2311 |
-
<
|
| 2312 |
-
|
| 2313 |
-
|
| 2314 |
-
|
| 2315 |
-
|
| 2316 |
-
|
| 2317 |
-
|
| 2318 |
-
|
| 2319 |
-
disabled={colunasXDisponiveis.length === 0}
|
| 2320 |
-
/>
|
| 2321 |
-
{todasXMarcadas ? 'Desmarcar todas' : 'Marcar todas'}
|
| 2322 |
-
</label>
|
| 2323 |
-
<span className="compact-selection-count">
|
| 2324 |
-
{colunasX.length}/{colunasXDisponiveis.length} selecionadas
|
| 2325 |
-
</span>
|
| 2326 |
-
</div>
|
| 2327 |
-
<div className="checkbox-inline-wrap">
|
| 2328 |
-
{colunasXDisponiveis.map((col) => (
|
| 2329 |
-
<label key={`x-${col}`} className="compact-checkbox">
|
| 2330 |
-
<input
|
| 2331 |
-
type="checkbox"
|
| 2332 |
-
checked={colunasX.includes(col)}
|
| 2333 |
-
onChange={() => onToggleColunaX(col)}
|
| 2334 |
-
/>
|
| 2335 |
-
{col}
|
| 2336 |
-
</label>
|
| 2337 |
-
))}
|
| 2338 |
</div>
|
| 2339 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2340 |
|
| 2341 |
-
|
| 2342 |
-
|
| 2343 |
-
|
| 2344 |
-
|
| 2345 |
-
|
| 2346 |
-
|
| 2347 |
-
|
| 2348 |
-
|
| 2349 |
-
|
| 2350 |
-
|
| 2351 |
-
|
| 2352 |
|
| 2353 |
-
|
| 2354 |
-
|
| 2355 |
-
|
| 2356 |
-
|
| 2357 |
-
|
| 2358 |
-
|
| 2359 |
-
|
| 2360 |
-
|
| 2361 |
-
|
| 2362 |
-
|
| 2363 |
-
|
| 2364 |
|
| 2365 |
-
|
| 2366 |
-
|
| 2367 |
-
|
| 2368 |
-
|
| 2369 |
-
|
| 2370 |
-
|
| 2371 |
-
|
| 2372 |
-
|
| 2373 |
-
|
| 2374 |
-
|
| 2375 |
-
|
| 2376 |
|
| 2377 |
-
|
| 2378 |
-
|
| 2379 |
-
|
| 2380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2381 |
{selection?.aviso_multicolinearidade?.visible ? (
|
| 2382 |
<div dangerouslySetInnerHTML={{ __html: selection.aviso_multicolinearidade.html }} />
|
| 2383 |
) : null}
|
|
@@ -2571,7 +2754,14 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 2571 |
</div>
|
| 2572 |
|
| 2573 |
<div className="row row-fit-transformacoes">
|
| 2574 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2575 |
{manualTransformPendente ? <span className="pending-apply-note">{pendingWarningText}</span> : null}
|
| 2576 |
</div>
|
| 2577 |
</>
|
|
@@ -2980,6 +3170,14 @@ export default function ElaboracaoTab({ sessionId }) {
|
|
| 2980 |
</>
|
| 2981 |
) : null}
|
| 2982 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2983 |
<LoadingOverlay show={loading} label="Processando dados..." />
|
| 2984 |
{error ? <div className="error-line">{error}</div> : null}
|
| 2985 |
</div>
|
|
|
|
| 1 |
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
| 2 |
import { api, downloadBlob } from '../api'
|
| 3 |
import Plotly from 'plotly.js-dist-min'
|
| 4 |
import DataTable from './DataTable'
|
|
|
|
| 593 |
const [section8Open, setSection8Open] = useState(false)
|
| 594 |
const [section10ManualOpen, setSection10ManualOpen] = useState(false)
|
| 595 |
const [section11Open, setSection11Open] = useState(false)
|
| 596 |
+
const [section6EditOpen, setSection6EditOpen] = useState(true)
|
| 597 |
|
| 598 |
const [fit, setFit] = useState(null)
|
| 599 |
const [tipoDispersao, setTipoDispersao] = useState('Variáveis Independentes Transformadas X Variável Dependente Transformada')
|
|
|
|
| 625 |
const classificarXReqRef = useRef(0)
|
| 626 |
const deleteConfirmTimersRef = useRef({})
|
| 627 |
const uploadInputRef = useRef(null)
|
| 628 |
+
const [disabledHint, setDisabledHint] = useState(null)
|
| 629 |
|
| 630 |
const mapaChoices = useMemo(() => ['Visualização Padrão', ...colunasNumericas], [colunasNumericas])
|
| 631 |
const colunasXDisponiveis = useMemo(
|
|
|
|
| 670 |
[periodoDadosMercadoPreview],
|
| 671 |
)
|
| 672 |
const pendingWarningText = 'Há alterações em campos que ainda não foram aplicadas.'
|
| 673 |
+
const semAlteracaoTooltipText = 'Não houve modificação para ser aplicada.'
|
| 674 |
const dataMercadoPendente = useMemo(
|
| 675 |
() => String(colunaDataMercado || '') !== String(colunaDataMercadoAplicada || ''),
|
| 676 |
[colunaDataMercado, colunaDataMercadoAplicada],
|
|
|
|
| 713 |
() => Boolean(selection) && Boolean(section10ManualOpen) && manualTransformSnapshotAtual !== manualTransformAppliedSnapshot,
|
| 714 |
[selection, section10ManualOpen, manualTransformSnapshotAtual, manualTransformAppliedSnapshot],
|
| 715 |
)
|
| 716 |
+
const podeAplicarDataMercado = useMemo(
|
| 717 |
+
() => dataMercadoPendente && Boolean(colunaDataMercado) && Boolean(periodoDadosMercadoPreview),
|
| 718 |
+
[dataMercadoPendente, colunaDataMercado, periodoDadosMercadoPreview],
|
| 719 |
+
)
|
| 720 |
+
const semAlteracaoDataMercado = useMemo(
|
| 721 |
+
() => !dataMercadoPendente && Boolean(colunaDataMercadoAplicada),
|
| 722 |
+
[dataMercadoPendente, colunaDataMercadoAplicada],
|
| 723 |
+
)
|
| 724 |
+
const semAlteracaoDependente = useMemo(
|
| 725 |
+
() => !dependentePendente && Boolean(colunaYDraft),
|
| 726 |
+
[dependentePendente, colunaYDraft],
|
| 727 |
+
)
|
| 728 |
+
const podeAplicarSelecao = useMemo(
|
| 729 |
+
() => selecaoPendente && !dependentePendente && Boolean(colunaY) && colunasX.length > 0,
|
| 730 |
+
[selecaoPendente, dependentePendente, colunaY, colunasX],
|
| 731 |
+
)
|
| 732 |
+
const semAlteracaoSelecao = useMemo(
|
| 733 |
+
() => !selecaoPendente && !dependentePendente && Boolean(colunaY) && colunasX.length > 0,
|
| 734 |
+
[selecaoPendente, dependentePendente, colunaY, colunasX],
|
| 735 |
+
)
|
| 736 |
+
const podeAplicarTransformacaoManual = useMemo(
|
| 737 |
+
() => manualTransformPendente,
|
| 738 |
+
[manualTransformPendente],
|
| 739 |
+
)
|
| 740 |
+
const semAlteracaoTransformacaoManual = useMemo(
|
| 741 |
+
() => !manualTransformPendente && Boolean(selection) && Boolean(section10ManualOpen),
|
| 742 |
+
[manualTransformPendente, selection, section10ManualOpen],
|
| 743 |
+
)
|
| 744 |
const outlierFiltrosSnapshotAtual = useMemo(
|
| 745 |
() => buildFiltrosSnapshot(filtros),
|
| 746 |
[filtros],
|
|
|
|
| 824 |
)
|
| 825 |
const baseCarregada = Boolean(dados)
|
| 826 |
|
| 827 |
+
const hideDisabledHint = useCallback(() => {
|
| 828 |
+
setDisabledHint(null)
|
| 829 |
+
}, [])
|
| 830 |
+
|
| 831 |
+
const onDisabledHintEnter = useCallback((event, showHint, hintText) => {
|
| 832 |
+
if (!showHint || !hintText || typeof window === 'undefined') {
|
| 833 |
+
setDisabledHint(null)
|
| 834 |
+
return
|
| 835 |
+
}
|
| 836 |
+
|
| 837 |
+
const anchor = event.currentTarget
|
| 838 |
+
if (!anchor || typeof anchor.getBoundingClientRect !== 'function') {
|
| 839 |
+
setDisabledHint(null)
|
| 840 |
+
return
|
| 841 |
+
}
|
| 842 |
+
|
| 843 |
+
const anchorRect = anchor.getBoundingClientRect()
|
| 844 |
+
const sectionEl = anchor.closest('.workflow-section')
|
| 845 |
+
const sectionRect = sectionEl?.getBoundingClientRect?.()
|
| 846 |
+
const containerRect = sectionRect || {
|
| 847 |
+
top: 0,
|
| 848 |
+
left: 0,
|
| 849 |
+
right: window.innerWidth,
|
| 850 |
+
bottom: window.innerHeight,
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
const tooltipWidth = 280
|
| 854 |
+
const tooltipHeight = 44
|
| 855 |
+
const gap = 10
|
| 856 |
+
const margin = 12
|
| 857 |
+
|
| 858 |
+
const distLeft = anchorRect.left - containerRect.left
|
| 859 |
+
const distRight = containerRect.right - anchorRect.right
|
| 860 |
+
const distTop = anchorRect.top - containerRect.top
|
| 861 |
+
const distBottom = containerRect.bottom - anchorRect.bottom
|
| 862 |
+
|
| 863 |
+
const openToRight = distLeft <= distRight
|
| 864 |
+
const openToTop = distBottom <= distTop
|
| 865 |
+
|
| 866 |
+
let left = openToRight ? anchorRect.left : anchorRect.right - tooltipWidth
|
| 867 |
+
let top = openToTop ? anchorRect.top - tooltipHeight - gap : anchorRect.bottom + gap
|
| 868 |
+
|
| 869 |
+
left = Math.max(margin, Math.min(left, window.innerWidth - tooltipWidth - margin))
|
| 870 |
+
top = Math.max(margin, Math.min(top, window.innerHeight - tooltipHeight - margin))
|
| 871 |
+
|
| 872 |
+
setDisabledHint({
|
| 873 |
+
text: String(hintText),
|
| 874 |
+
left,
|
| 875 |
+
top,
|
| 876 |
+
width: tooltipWidth,
|
| 877 |
+
})
|
| 878 |
+
}, [])
|
| 879 |
+
|
| 880 |
useEffect(() => {
|
| 881 |
if (coordsInfo && !coordsInfo.tem_coords) {
|
| 882 |
setCoordsMode('menu')
|
|
|
|
| 1046 |
setPeriodoDadosMercadoPreview(null)
|
| 1047 |
setDataMercadoError('')
|
| 1048 |
setSelection(null)
|
| 1049 |
+
setSection6EditOpen(true)
|
| 1050 |
setFit(null)
|
| 1051 |
setFiltros(defaultFiltros())
|
| 1052 |
setOutliersTexto('')
|
|
|
|
| 1083 |
|
| 1084 |
function applySelectionResponse(resp) {
|
| 1085 |
setSelection(resp)
|
| 1086 |
+
setSection6EditOpen(false)
|
| 1087 |
setSection8Open(false)
|
| 1088 |
setSection10ManualOpen(false)
|
| 1089 |
setTransformacoesAplicadas(null)
|
|
|
|
| 1342 |
setDicotomicas(proximasDicotomicas)
|
| 1343 |
setCodigoAlocado(proximoCodigoAlocado)
|
| 1344 |
setPercentuais(proximosPercentuais)
|
| 1345 |
+
setSection6EditOpen(true)
|
| 1346 |
setSelectionAppliedSnapshot(buildSelectionSnapshot({ coluna_y: proximaColunaY }))
|
| 1347 |
setSelection(null)
|
| 1348 |
setFit(null)
|
|
|
|
| 1482 |
const resp = await api.applySelection(payload)
|
| 1483 |
applySelectionResponse(resp)
|
| 1484 |
setSelectionAppliedSnapshot(buildSelectionSnapshot(payload))
|
| 1485 |
+
setSection6EditOpen(false)
|
| 1486 |
setFit(null)
|
| 1487 |
setOutlierFiltrosAplicadosSnapshot(buildFiltrosSnapshot(defaultFiltros()))
|
| 1488 |
setOutlierTextosAplicadosSnapshot(buildOutlierTextSnapshot('', ''))
|
|
|
|
| 1620 |
setOutliersAnteriores([])
|
| 1621 |
setIteracao(1)
|
| 1622 |
setSelection(null)
|
| 1623 |
+
setSection6EditOpen(true)
|
| 1624 |
setFit(null)
|
| 1625 |
setTransformacoesAplicadas(null)
|
| 1626 |
setOrigemTransformacoes(null)
|
|
|
|
| 2354 |
</select>
|
| 2355 |
</div>
|
| 2356 |
<div className="row market-date-actions-row">
|
| 2357 |
+
<div className="resumo-outliers-box market-date-period-row">
|
| 2358 |
Período identificado: {periodoDadosMercadoPreviewTexto}
|
| 2359 |
</div>
|
| 2360 |
+
<div className="row market-date-apply-row">
|
| 2361 |
+
<span
|
| 2362 |
+
className={`button-tooltip-wrap${semAlteracaoDataMercado ? ' is-disabled-hint' : ''}`}
|
| 2363 |
+
title={semAlteracaoDataMercado ? semAlteracaoTooltipText : ''}
|
| 2364 |
+
onMouseEnter={(event) => onDisabledHintEnter(event, semAlteracaoDataMercado, semAlteracaoTooltipText)}
|
| 2365 |
+
onMouseLeave={hideDisabledHint}
|
| 2366 |
+
>
|
| 2367 |
+
<button
|
| 2368 |
+
type="button"
|
| 2369 |
+
onClick={onAplicarColunaDataMercado}
|
| 2370 |
+
disabled={loading || dataMercadoLoading || !podeAplicarDataMercado}
|
| 2371 |
+
>
|
| 2372 |
+
Aplicar
|
| 2373 |
+
</button>
|
| 2374 |
+
</span>
|
| 2375 |
+
{dataMercadoPendente ? <span className="pending-apply-note">{pendingWarningText}</span> : null}
|
| 2376 |
+
</div>
|
| 2377 |
+
<div className="section1-empty-hint">Selecionado: {colunaDataMercado || '-'}</div>
|
| 2378 |
</div>
|
| 2379 |
{dataMercadoError ? <div className="error-line inline-error">{dataMercadoError}</div> : null}
|
| 2380 |
</div>
|
|
|
|
| 2389 |
<option key={col} value={col}>{col}</option>
|
| 2390 |
))}
|
| 2391 |
</select>
|
| 2392 |
+
</div>
|
| 2393 |
+
<div className="row section5-apply-row">
|
| 2394 |
+
<span
|
| 2395 |
+
className={`button-tooltip-wrap${semAlteracaoDependente ? ' is-disabled-hint' : ''}`}
|
| 2396 |
+
title={semAlteracaoDependente ? semAlteracaoTooltipText : ''}
|
| 2397 |
+
onMouseEnter={(event) => onDisabledHintEnter(event, semAlteracaoDependente, semAlteracaoTooltipText)}
|
| 2398 |
+
onMouseLeave={hideDisabledHint}
|
| 2399 |
>
|
| 2400 |
+
<button
|
| 2401 |
+
type="button"
|
| 2402 |
+
onClick={onAplicarVariavelDependente}
|
| 2403 |
+
disabled={loading || !dependentePendente}
|
| 2404 |
+
>
|
| 2405 |
+
Aplicar
|
| 2406 |
+
</button>
|
| 2407 |
+
</span>
|
| 2408 |
{dependentePendente ? <span className="pending-apply-note">{pendingWarningText}</span> : null}
|
| 2409 |
</div>
|
| 2410 |
+
<div className="section1-empty-hint">Selecionado: {colunaYDraft || '-'}</div>
|
| 2411 |
</SectionBlock>
|
| 2412 |
|
| 2413 |
<SectionBlock step="6" title="Selecionar Variáveis Independentes" subtitle="Escolha regressoras e grupos de tipologia.">
|
|
|
|
| 2416 |
Aplique a variável dependente na etapa anterior para liberar as opções de variáveis independentes.
|
| 2417 |
</div>
|
| 2418 |
) : null}
|
| 2419 |
+
{colunaY ? (
|
| 2420 |
+
<div className="manual-transform-toggle section6-toggle-wrap">
|
| 2421 |
+
<button
|
| 2422 |
+
type="button"
|
| 2423 |
+
className={section6EditOpen ? 'btn-manual-toggle active' : 'btn-manual-toggle'}
|
| 2424 |
+
onClick={() => setSection6EditOpen((prev) => !prev)}
|
| 2425 |
+
>
|
| 2426 |
+
{section6EditOpen ? 'Ocultar edição de variáveis independentes' : 'Alterar variáveis independentes'}
|
| 2427 |
+
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2428 |
</div>
|
| 2429 |
+
) : null}
|
| 2430 |
+
{colunaY && section6EditOpen ? (
|
| 2431 |
+
<>
|
| 2432 |
+
<div className="compact-option-group compact-option-group-x">
|
| 2433 |
+
<h4>Variáveis Independentes (X)</h4>
|
| 2434 |
+
<div className="checkbox-inline-wrap checkbox-inline-wrap-tools">
|
| 2435 |
+
<label className="compact-checkbox compact-checkbox-toggle-all">
|
| 2436 |
+
<input
|
| 2437 |
+
ref={marcarTodasXRef}
|
| 2438 |
+
type="checkbox"
|
| 2439 |
+
checked={todasXMarcadas}
|
| 2440 |
+
onChange={onToggleTodasX}
|
| 2441 |
+
disabled={colunasXDisponiveis.length === 0}
|
| 2442 |
+
/>
|
| 2443 |
+
{todasXMarcadas ? 'Desmarcar todas' : 'Marcar todas'}
|
| 2444 |
+
</label>
|
| 2445 |
+
<span className="compact-selection-count">
|
| 2446 |
+
{colunasX.length}/{colunasXDisponiveis.length} selecionadas
|
| 2447 |
+
</span>
|
| 2448 |
+
</div>
|
| 2449 |
+
<div className="checkbox-inline-wrap">
|
| 2450 |
+
{colunasXDisponiveis.map((col) => (
|
| 2451 |
+
<label key={`x-${col}`} className="compact-checkbox">
|
| 2452 |
+
<input
|
| 2453 |
+
type="checkbox"
|
| 2454 |
+
checked={colunasX.includes(col)}
|
| 2455 |
+
onChange={() => onToggleColunaX(col)}
|
| 2456 |
+
/>
|
| 2457 |
+
{col}
|
| 2458 |
+
</label>
|
| 2459 |
+
))}
|
| 2460 |
+
</div>
|
| 2461 |
+
</div>
|
| 2462 |
|
| 2463 |
+
<div className="compact-option-group compact-option-group-dicotomicas">
|
| 2464 |
+
<h4>Variáveis Dicotômicas (0/1)</h4>
|
| 2465 |
+
<div className="checkbox-inline-wrap">
|
| 2466 |
+
{colunasX.map((col) => (
|
| 2467 |
+
<label key={`d-${col}`} className="compact-checkbox">
|
| 2468 |
+
<input type="checkbox" checked={dicotomicas.includes(col)} onChange={() => toggleSelection(setDicotomicas, col)} />
|
| 2469 |
+
{col}
|
| 2470 |
+
</label>
|
| 2471 |
+
))}
|
| 2472 |
+
</div>
|
| 2473 |
+
</div>
|
| 2474 |
|
| 2475 |
+
<div className="compact-option-group compact-option-group-codigo">
|
| 2476 |
+
<h4>Variáveis de Código Alocado/Ajustado</h4>
|
| 2477 |
+
<div className="checkbox-inline-wrap">
|
| 2478 |
+
{colunasX.map((col) => (
|
| 2479 |
+
<label key={`c-${col}`} className="compact-checkbox">
|
| 2480 |
+
<input type="checkbox" checked={codigoAlocado.includes(col)} onChange={() => toggleSelection(setCodigoAlocado, col)} />
|
| 2481 |
+
{col}
|
| 2482 |
+
</label>
|
| 2483 |
+
))}
|
| 2484 |
+
</div>
|
| 2485 |
+
</div>
|
| 2486 |
|
| 2487 |
+
<div className="compact-option-group compact-option-group-percentuais">
|
| 2488 |
+
<h4>Variáveis Percentuais (0 a 1)</h4>
|
| 2489 |
+
<div className="checkbox-inline-wrap">
|
| 2490 |
+
{colunasX.map((col) => (
|
| 2491 |
+
<label key={`p-${col}`} className="compact-checkbox">
|
| 2492 |
+
<input type="checkbox" checked={percentuais.includes(col)} onChange={() => toggleSelection(setPercentuais, col)} />
|
| 2493 |
+
{col}
|
| 2494 |
+
</label>
|
| 2495 |
+
))}
|
| 2496 |
+
</div>
|
| 2497 |
+
</div>
|
| 2498 |
|
| 2499 |
+
<div className="row">
|
| 2500 |
+
<span
|
| 2501 |
+
className={`button-tooltip-wrap${semAlteracaoSelecao ? ' is-disabled-hint' : ''}`}
|
| 2502 |
+
title={semAlteracaoSelecao ? semAlteracaoTooltipText : ''}
|
| 2503 |
+
onMouseEnter={(event) => onDisabledHintEnter(event, semAlteracaoSelecao, semAlteracaoTooltipText)}
|
| 2504 |
+
onMouseLeave={hideDisabledHint}
|
| 2505 |
+
>
|
| 2506 |
+
<button onClick={onApplySelection} disabled={loading || !podeAplicarSelecao}>Aplicar seleção</button>
|
| 2507 |
+
</span>
|
| 2508 |
+
{selecaoPendente ? <span className="pending-apply-note">{pendingWarningText}</span> : null}
|
| 2509 |
+
</div>
|
| 2510 |
+
</>
|
| 2511 |
+
) : null}
|
| 2512 |
+
{colunaY ? (
|
| 2513 |
+
<div className="section6-selected-summary">
|
| 2514 |
+
<div className="section6-summary-group">
|
| 2515 |
+
<div className="section6-summary-label">Independentes:</div>
|
| 2516 |
+
{colunasX.length > 0 ? (
|
| 2517 |
+
<div className="checkbox-inline-wrap">
|
| 2518 |
+
{colunasX.map((coluna) => (
|
| 2519 |
+
<span key={`selected-x-${coluna}`} className="compact-chip">{coluna}</span>
|
| 2520 |
+
))}
|
| 2521 |
+
</div>
|
| 2522 |
+
) : (
|
| 2523 |
+
<div className="section1-empty-hint">Nenhuma.</div>
|
| 2524 |
+
)}
|
| 2525 |
+
</div>
|
| 2526 |
+
<div className="section6-summary-group">
|
| 2527 |
+
<div className="section6-summary-label">Dicotômicas:</div>
|
| 2528 |
+
{dicotomicas.length > 0 ? (
|
| 2529 |
+
<div className="checkbox-inline-wrap">
|
| 2530 |
+
{dicotomicas.map((coluna) => (
|
| 2531 |
+
<span key={`selected-d-${coluna}`} className="compact-chip">{coluna}</span>
|
| 2532 |
+
))}
|
| 2533 |
+
</div>
|
| 2534 |
+
) : (
|
| 2535 |
+
<div className="section1-empty-hint">Nenhuma.</div>
|
| 2536 |
+
)}
|
| 2537 |
+
</div>
|
| 2538 |
+
<div className="section6-summary-group">
|
| 2539 |
+
<div className="section6-summary-label">Código alocado/ajustado:</div>
|
| 2540 |
+
{codigoAlocado.length > 0 ? (
|
| 2541 |
+
<div className="checkbox-inline-wrap">
|
| 2542 |
+
{codigoAlocado.map((coluna) => (
|
| 2543 |
+
<span key={`selected-c-${coluna}`} className="compact-chip">{coluna}</span>
|
| 2544 |
+
))}
|
| 2545 |
+
</div>
|
| 2546 |
+
) : (
|
| 2547 |
+
<div className="section1-empty-hint">Nenhuma.</div>
|
| 2548 |
+
)}
|
| 2549 |
+
</div>
|
| 2550 |
+
<div className="section6-summary-group">
|
| 2551 |
+
<div className="section6-summary-label">Percentuais:</div>
|
| 2552 |
+
{percentuais.length > 0 ? (
|
| 2553 |
+
<div className="checkbox-inline-wrap">
|
| 2554 |
+
{percentuais.map((coluna) => (
|
| 2555 |
+
<span key={`selected-p-${coluna}`} className="compact-chip">{coluna}</span>
|
| 2556 |
+
))}
|
| 2557 |
+
</div>
|
| 2558 |
+
) : (
|
| 2559 |
+
<div className="section1-empty-hint">Nenhuma.</div>
|
| 2560 |
+
)}
|
| 2561 |
+
</div>
|
| 2562 |
+
</div>
|
| 2563 |
+
) : null}
|
| 2564 |
{selection?.aviso_multicolinearidade?.visible ? (
|
| 2565 |
<div dangerouslySetInnerHTML={{ __html: selection.aviso_multicolinearidade.html }} />
|
| 2566 |
) : null}
|
|
|
|
| 2754 |
</div>
|
| 2755 |
|
| 2756 |
<div className="row row-fit-transformacoes">
|
| 2757 |
+
<span
|
| 2758 |
+
className={`button-tooltip-wrap${semAlteracaoTransformacaoManual ? ' is-disabled-hint' : ''}`}
|
| 2759 |
+
title={semAlteracaoTransformacaoManual ? semAlteracaoTooltipText : ''}
|
| 2760 |
+
onMouseEnter={(event) => onDisabledHintEnter(event, semAlteracaoTransformacaoManual, semAlteracaoTooltipText)}
|
| 2761 |
+
onMouseLeave={hideDisabledHint}
|
| 2762 |
+
>
|
| 2763 |
+
<button className="btn-fit-model" onClick={onFitModel} disabled={loading || !podeAplicarTransformacaoManual}>Aplicar transformações e ajustar modelo</button>
|
| 2764 |
+
</span>
|
| 2765 |
{manualTransformPendente ? <span className="pending-apply-note">{pendingWarningText}</span> : null}
|
| 2766 |
</div>
|
| 2767 |
</>
|
|
|
|
| 3170 |
</>
|
| 3171 |
) : null}
|
| 3172 |
|
| 3173 |
+
{disabledHint ? (
|
| 3174 |
+
<div
|
| 3175 |
+
className="disabled-change-tooltip"
|
| 3176 |
+
style={{ left: `${disabledHint.left}px`, top: `${disabledHint.top}px`, width: `${disabledHint.width}px` }}
|
| 3177 |
+
>
|
| 3178 |
+
{disabledHint.text}
|
| 3179 |
+
</div>
|
| 3180 |
+
) : null}
|
| 3181 |
<LoadingOverlay show={loading} label="Processando dados..." />
|
| 3182 |
{error ? <div className="error-line">{error}</div> : null}
|
| 3183 |
</div>
|
frontend/src/styles.css
CHANGED
|
@@ -1860,6 +1860,10 @@ button.btn-upload-select {
|
|
| 1860 |
margin: 8px 0 10px;
|
| 1861 |
}
|
| 1862 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1863 |
.btn-manual-toggle {
|
| 1864 |
min-width: 320px;
|
| 1865 |
}
|
|
@@ -1872,6 +1876,64 @@ button.btn-upload-select {
|
|
| 1872 |
--btn-shadow-strong: rgba(86, 105, 122, 0.24);
|
| 1873 |
}
|
| 1874 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1875 |
.transform-suggestion-item {
|
| 1876 |
display: grid;
|
| 1877 |
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
@@ -2328,19 +2390,25 @@ button.btn-upload-select {
|
|
| 2328 |
}
|
| 2329 |
|
| 2330 |
.market-date-actions-row {
|
| 2331 |
-
align-items:
|
| 2332 |
-
justify-content:
|
| 2333 |
gap: 10px;
|
| 2334 |
-
flex-wrap:
|
|
|
|
| 2335 |
}
|
| 2336 |
|
| 2337 |
-
.market-date-
|
| 2338 |
margin-top: 0;
|
| 2339 |
min-height: 38px;
|
| 2340 |
display: inline-flex;
|
| 2341 |
align-items: center;
|
| 2342 |
}
|
| 2343 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2344 |
.pending-apply-note {
|
| 2345 |
display: inline-flex;
|
| 2346 |
align-items: center;
|
|
|
|
| 1860 |
margin: 8px 0 10px;
|
| 1861 |
}
|
| 1862 |
|
| 1863 |
+
.section6-toggle-wrap {
|
| 1864 |
+
margin-bottom: 12px;
|
| 1865 |
+
}
|
| 1866 |
+
|
| 1867 |
.btn-manual-toggle {
|
| 1868 |
min-width: 320px;
|
| 1869 |
}
|
|
|
|
| 1876 |
--btn-shadow-strong: rgba(86, 105, 122, 0.24);
|
| 1877 |
}
|
| 1878 |
|
| 1879 |
+
.section6-selected-summary {
|
| 1880 |
+
margin-top: 8px;
|
| 1881 |
+
display: grid;
|
| 1882 |
+
gap: 8px;
|
| 1883 |
+
}
|
| 1884 |
+
|
| 1885 |
+
.section6-summary-group {
|
| 1886 |
+
display: grid;
|
| 1887 |
+
gap: 5px;
|
| 1888 |
+
}
|
| 1889 |
+
|
| 1890 |
+
.section6-summary-label {
|
| 1891 |
+
font-size: 0.79rem;
|
| 1892 |
+
font-weight: 700;
|
| 1893 |
+
color: #4d647b;
|
| 1894 |
+
}
|
| 1895 |
+
|
| 1896 |
+
.compact-chip {
|
| 1897 |
+
display: inline-flex;
|
| 1898 |
+
align-items: center;
|
| 1899 |
+
gap: 5px;
|
| 1900 |
+
padding: 4px 7px;
|
| 1901 |
+
border: 1px solid #dfe8f1;
|
| 1902 |
+
border-radius: 8px;
|
| 1903 |
+
background: #fbfdff;
|
| 1904 |
+
font-size: 0.83rem;
|
| 1905 |
+
font-weight: 600;
|
| 1906 |
+
color: #3a4f64;
|
| 1907 |
+
line-height: 1.15;
|
| 1908 |
+
}
|
| 1909 |
+
|
| 1910 |
+
.button-tooltip-wrap {
|
| 1911 |
+
position: relative;
|
| 1912 |
+
display: inline-flex;
|
| 1913 |
+
}
|
| 1914 |
+
|
| 1915 |
+
.button-tooltip-wrap.is-disabled-hint {
|
| 1916 |
+
cursor: not-allowed;
|
| 1917 |
+
}
|
| 1918 |
+
|
| 1919 |
+
.button-tooltip-wrap.is-disabled-hint > button:disabled {
|
| 1920 |
+
pointer-events: none;
|
| 1921 |
+
}
|
| 1922 |
+
|
| 1923 |
+
.disabled-change-tooltip {
|
| 1924 |
+
position: fixed;
|
| 1925 |
+
z-index: 3500;
|
| 1926 |
+
pointer-events: none;
|
| 1927 |
+
padding: 6px 10px;
|
| 1928 |
+
border-radius: 8px;
|
| 1929 |
+
background: #3f5368;
|
| 1930 |
+
color: #fff;
|
| 1931 |
+
font-size: 0.76rem;
|
| 1932 |
+
line-height: 1.25;
|
| 1933 |
+
text-align: left;
|
| 1934 |
+
box-shadow: 0 8px 18px rgba(28, 46, 66, 0.26);
|
| 1935 |
+
}
|
| 1936 |
+
|
| 1937 |
.transform-suggestion-item {
|
| 1938 |
display: grid;
|
| 1939 |
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
|
|
| 2390 |
}
|
| 2391 |
|
| 2392 |
.market-date-actions-row {
|
| 2393 |
+
align-items: flex-start;
|
| 2394 |
+
justify-content: flex-start;
|
| 2395 |
gap: 10px;
|
| 2396 |
+
flex-wrap: nowrap;
|
| 2397 |
+
flex-direction: column;
|
| 2398 |
}
|
| 2399 |
|
| 2400 |
+
.market-date-period-row {
|
| 2401 |
margin-top: 0;
|
| 2402 |
min-height: 38px;
|
| 2403 |
display: inline-flex;
|
| 2404 |
align-items: center;
|
| 2405 |
}
|
| 2406 |
|
| 2407 |
+
.market-date-apply-row,
|
| 2408 |
+
.section5-apply-row {
|
| 2409 |
+
margin-bottom: 0;
|
| 2410 |
+
}
|
| 2411 |
+
|
| 2412 |
.pending-apply-note {
|
| 2413 |
display: inline-flex;
|
| 2414 |
align-items: center;
|