| |
|
| |
|
| |
|
| | 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() |