Spaces:
Running
Running
| # pages/Inbox_Admin.py | |
| # -*- coding: utf-8 -*- | |
| import streamlit as st | |
| from datetime import datetime | |
| from sqlalchemy import func | |
| # Model | |
| from models import IOIRunSugestao | |
| # (Opcional) auditoria | |
| try: | |
| from utils_auditoria import registrar_log | |
| except Exception: | |
| registrar_log = None | |
| # ------------- CONFIG BÁSICA ------------- | |
| st.set_page_config(page_title="📬 Inbox Admin • IOI-RUN", layout="wide") | |
| STATUS_PENDENTE = "pendente" | |
| STATUS_RESPONDIDA = "respondida" | |
| # ------------- Sessão de banco ciente do ambiente ------------- | |
| def _get_db_session(): | |
| """ | |
| Retorna uma sessão de banco consistente com o ambiente atual. | |
| Tenta usar o db_router (se presente); senão, cai para SessionLocal(). | |
| """ | |
| try: | |
| from db_router import get_session_for_current_db | |
| return get_session_for_current_db() | |
| except Exception: | |
| pass | |
| try: | |
| from banco import SessionLocal | |
| return SessionLocal() | |
| except Exception as e: | |
| st.error(f"Banco indisponível: {e}") | |
| raise | |
| def _debug_banco_caption(): | |
| """Mostra em qual banco estamos (Produção/Teste/Treinamento).""" | |
| try: | |
| from db_router import current_db_choice, bank_label | |
| choice = current_db_choice() | |
| label = bank_label(choice) | |
| st.caption(f"🗄️ Banco ativo: **{label}**") | |
| except Exception: | |
| st.caption("🗄️ Banco ativo: **default**") | |
| # ------------- Guarda de rota (somente admin) ------------- | |
| def _ensure_admin(): | |
| perfil = (st.session_state.get("perfil") or "").strip().lower() | |
| if perfil != "admin": | |
| st.error("Acesso negado. Esta página é restrita a administradores.") | |
| st.stop() | |
| # ------------- Página ------------- | |
| def main(): | |
| _ensure_admin() | |
| st.title("📬 Caixa de Entrada • IOI‑RUN (Admin)") | |
| st.caption("Responda sugestões dos usuários em uma página separada, sem interferência do app principal.") | |
| _debug_banco_caption() | |
| # Estados persistentes exclusivos desta página (prefixo 'adm_inbox_') | |
| st.session_state.setdefault("adm_inbox_area", "todos") | |
| st.session_state.setdefault("adm_inbox_status", STATUS_PENDENTE) | |
| st.session_state.setdefault("adm_inbox_usuario", "") | |
| st.session_state.setdefault("adm_inbox_nonce", 0) | |
| AREAS = ["todos", "WMS", "FPSO", "UI/UX", "Relatórios", "Integrações", "Performance", "Segurança", "Outros"] | |
| STATUS = [STATUS_PENDENTE, STATUS_RESPONDIDA, "todos"] | |
| # ------------- Filtros ------------- | |
| col_f1, col_f2, col_f3, col_f4 = st.columns([1, 1, 1, 0.6]) | |
| col_f1.selectbox( | |
| "Área/Tema", | |
| AREAS, | |
| key="adm_inbox_area", | |
| index=AREAS.index(st.session_state["adm_inbox_area"]) if st.session_state["adm_inbox_area"] in AREAS else 0 | |
| ) | |
| col_f2.selectbox( | |
| "Status", | |
| STATUS, | |
| key="adm_inbox_status", | |
| index=STATUS.index(st.session_state["adm_inbox_status"]) if st.session_state["adm_inbox_status"] in STATUS else 0 | |
| ) | |
| col_f3.text_input( | |
| "Filtrar por usuário (login exato)", | |
| key="adm_inbox_usuario", | |
| value=st.session_state["adm_inbox_usuario"] | |
| ) | |
| if col_f4.button("🔄 Atualizar lista"): | |
| st.session_state["adm_inbox_nonce"] += 1 | |
| st.rerun() | |
| # ------------- Consulta ------------- | |
| db = _get_db_session() | |
| try: | |
| q = db.query(IOIRunSugestao) | |
| if st.session_state["adm_inbox_area"] != "todos": | |
| q = q.filter(IOIRunSugestao.area == st.session_state["adm_inbox_area"]) | |
| if st.session_state["adm_inbox_status"] != "todos": | |
| q = q.filter(func.lower(IOIRunSugestao.status) == st.session_state["adm_inbox_status"]) | |
| if (st.session_state["adm_inbox_usuario"] or "").strip(): | |
| q = q.filter(IOIRunSugestao.usuario == (st.session_state["adm_inbox_usuario"] or "").strip()) | |
| sugestoes = q.order_by(IOIRunSugestao.data_envio.desc()).all() | |
| except Exception as e: | |
| st.error(f"Erro ao consultar sugestões: {e}") | |
| sugestoes = [] | |
| # ------------- Lista / Edição ------------- | |
| if not sugestoes: | |
| st.info("Nenhuma sugestão encontrada para os filtros aplicados.") | |
| else: | |
| for s in sugestoes: | |
| dt_envio = s.data_envio.strftime("%d/%m/%Y %H:%M") if s.data_envio else "—" | |
| titulo = f"📩 {dt_envio} — {s.usuario} — Status: {s.status or '—'}" | |
| if s.area: | |
| titulo += f" — Área: {s.area}" | |
| with st.expander(titulo, expanded=False): | |
| st.markdown("**Sugestão:**") | |
| st.write(s.mensagem or "—") | |
| with st.form(key=f"adm_inbox_form_{s.id}", clear_on_submit=False): | |
| resposta_txt = st.text_area( | |
| f"Responder ao usuário ({s.usuario}) — ID {s.id}", | |
| value=s.resposta or "", | |
| key=f"adm_inbox_resposta_{s.id}", | |
| placeholder="Digite sua resposta para este usuário…", | |
| height=140 | |
| ) | |
| col_a1, col_a2 = st.columns([1, 1]) | |
| enviar = col_a1.form_submit_button("📤 Enviar resposta") | |
| pendenciar = col_a2.form_submit_button("⏳ Marcar como pendente") | |
| if enviar: | |
| try: | |
| s.resposta = (resposta_txt or "").strip() | |
| s.status = STATUS_RESPONDIDA if s.resposta else STATUS_PENDENTE | |
| s.data_resposta = datetime.now() if s.resposta else None | |
| s.responsavel = st.session_state.get("usuario") | |
| db.add(s) | |
| db.commit() | |
| # Auditoria (opcional) | |
| if registrar_log and s.resposta: | |
| try: | |
| registrar_log( | |
| usuario=st.session_state.get("usuario"), | |
| acao=f"Respondeu sugestão IOI‑RUN (ID {s.id}) para {s.usuario}", | |
| tabela="ioirun_sugestao", | |
| registro_id=s.id | |
| ) | |
| except Exception: | |
| pass | |
| st.success("Resposta registrada com sucesso! (Agora em 'respondida')") | |
| st.rerun() | |
| except Exception as e: | |
| db.rollback() | |
| st.error(f"Erro ao salvar resposta: {e}") | |
| if pendenciar: | |
| try: | |
| s.status = STATUS_PENDENTE | |
| s.resposta = None | |
| s.data_resposta = None | |
| s.responsavel = None | |
| db.add(s) | |
| db.commit() | |
| st.info("Sugestão marcada como pendente novamente.") | |
| st.rerun() | |
| except Exception as e: | |
| db.rollback() | |
| st.error(f"Erro ao alterar status: {e}") | |
| st.markdown("---") | |
| st.caption("Use o **menu lateral** para navegar para outros módulos.") | |
| try: | |
| db.close() | |
| except Exception: | |
| pass | |
| if __name__ == "__main__": | |
| main() |