|
|
|
|
|
|
|
|
|
|
|
import streamlit as st
|
|
|
from datetime import datetime
|
|
|
from sqlalchemy import func
|
|
|
|
|
|
|
|
|
from models import IOIRunSugestao
|
|
|
|
|
|
|
|
|
try:
|
|
|
from utils_auditoria import registrar_log
|
|
|
except Exception:
|
|
|
registrar_log = None
|
|
|
|
|
|
|
|
|
st.set_page_config(page_title="📬 Inbox Admin • IOI-RUN", layout="wide")
|
|
|
|
|
|
STATUS_PENDENTE = "pendente"
|
|
|
STATUS_RESPONDIDA = "respondida"
|
|
|
|
|
|
|
|
|
|
|
|
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**")
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
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"]
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
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 = []
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
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() |