IOI-RUN / Inbox_Admin.py
Roudrigus's picture
Upload 82 files
0f0ef8d verified
# 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()