feat: adiciona suporte para análise em background e processamento de resultados pendentes

This commit is contained in:
FelipeCN
2026-03-03 10:16:50 -03:00
parent dedb6a72c2
commit 2c08f237e9
3 changed files with 181 additions and 43 deletions
+51 -36
View File
@@ -1,6 +1,9 @@
use crate::application::usecases::importar_arquivo::{importar_csv, importar_xlsx};
use crate::application::usecases::executar_analise::{
expandir_analise, pre_analisar, series_com_intervalo_excessivo,
};
use crate::domain::entities::layout::{Layout, TipoArquivo};
use crate::ui::app::{App, EstadoApp};
use crate::ui::app::{App, EstadoApp, ResultadoPendente};
use egui::{Context, Ui};
/// Renderiza a tela de configuração de colunas.
@@ -93,7 +96,7 @@ pub fn renderizar(ui: &mut Ui, ctx: &Context, app: &mut App) {
ui.add_enabled_ui(valido && app.caminho_arquivo.is_some(), |ui| {
if ui.button("▶ Importar e Analisar").clicked() {
executar_importacao(app);
executar_importacao(app, ctx);
}
});
@@ -368,49 +371,61 @@ fn verificar_duplicados(indices: &[(String, usize)], erros: &mut Vec<String>) {
}
}
fn executar_importacao(app: &mut App) {
fn executar_importacao(app: &mut App, ctx: &egui::Context) {
let caminho = match &app.caminho_arquivo {
Some(p) => p.clone(),
None => return,
};
let resultado = match app.tipo_arquivo_atual.clone() {
TipoArquivo::Csv => {
importar_csv(&caminho, &app.layout_csv_atual).map_err(|e| e.to_string())
}
TipoArquivo::Xlsx => {
importar_xlsx(&caminho, &app.layout_xlsx_atual).map_err(|e| e.to_string())
}
};
let tipo = app.tipo_arquivo_atual.clone();
let layout_csv = app.layout_csv_atual.clone();
let layout_xlsx = app.layout_xlsx_atual.clone();
match resultado {
Ok(res) => {
if res.notas.is_empty() {
app.exibir_aviso("Aviso", "Nenhuma nota válida encontrada no arquivo.");
return;
}
let (tx, rx) = std::sync::mpsc::channel();
app.resultado_pendente = Some(rx);
app.estado = EstadoApp::Analisando;
ctx.request_repaint();
let avisos = res.avisos.clone();
app.notas_importadas = res.notas;
app.avisos_importacao = if avisos.tem_avisos() {
Some(avisos.clone())
} else {
None
};
std::thread::spawn(move || {
// 1. Importar arquivo
let res_importacao = match tipo {
TipoArquivo::Csv => importar_csv(&caminho, &layout_csv).map_err(|e| e.to_string()),
TipoArquivo::Xlsx => importar_xlsx(&caminho, &layout_xlsx).map_err(|e| e.to_string()),
};
// Executar análise
app.executar_analise();
let res = match res_importacao {
Err(e) => ResultadoPendente::Erro(e),
Ok(importado) => {
if importado.notas.is_empty() {
ResultadoPendente::Vazio
} else {
let avisos = importado.avisos.clone();
let notas = importado.notas;
// Exibir avisos consolidados após análise
if let Some(av) = &app.avisos_importacao {
if av.tem_avisos() {
let linhas = av.linhas_para_exibir().join("\n");
app.exibir_aviso("Avisos de Importação", linhas);
// 2. Pré-análise
let pre = pre_analisar(&notas);
let excessivos = series_com_intervalo_excessivo(&pre);
if !excessivos.is_empty() {
ResultadoPendente::AguardandoConfirmacao {
pre,
series_excessivas: excessivos,
avisos,
notas,
}
} else {
// 3. Expandir faltantes
let resultado = expandir_analise(pre, &notas);
ResultadoPendente::Concluido {
resultado,
avisos: Some(avisos),
notas: Some(notas),
}
}
}
}
}
Err(e) => {
app.exibir_erro(format!("Erro ao importar arquivo: {}", e));
}
}
};
let _ = tx.send(res);
});
}