159 lines
6.4 KiB
Python
159 lines
6.4 KiB
Python
import pandas as pd
|
|
import streamlit as st
|
|
|
|
from functions import (
|
|
add_tox_indicator,
|
|
delete_client,
|
|
fetch_all_ingredients,
|
|
fetch_clients,
|
|
)
|
|
|
|
st.title("Impostazioni")
|
|
|
|
tab_tox, tab_ingredienti, tab_clienti = st.tabs([
|
|
"Indicatore Tox Custom",
|
|
"Inventario Ingredienti",
|
|
"Gestione Clienti",
|
|
])
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# TAB 1 — Indicatore Tox Custom
|
|
# ---------------------------------------------------------------------------
|
|
with tab_tox:
|
|
st.subheader("Aggiungi indicatore tossicologico custom")
|
|
|
|
with st.form("form_tox_indicator"):
|
|
cas = st.text_input("CAS Number", placeholder="es. 56-81-5")
|
|
col1, col2 = st.columns(2)
|
|
with col1:
|
|
indicator = st.selectbox("Indicatore", ["NOAEL", "LOAEL", "LD50"])
|
|
value = st.number_input("Valore", min_value=0.0, step=0.1)
|
|
unit = st.text_input("Unità", placeholder="es. mg/kg bw/day")
|
|
with col2:
|
|
route = st.text_input("Via di esposizione", placeholder="es. oral, dermal")
|
|
toxicity_type = st.selectbox(
|
|
"Tipo tossicità",
|
|
["", "repeated_dose_toxicity", "acute_toxicity"],
|
|
format_func=lambda x: x if x else "— non specificato —"
|
|
)
|
|
ref = st.text_input("Riferimento / Fonte", placeholder="es. Studio interno 2024")
|
|
|
|
submitted = st.form_submit_button("Aggiungi indicatore", type="primary")
|
|
|
|
if submitted:
|
|
if not cas or not unit or not route:
|
|
st.error("CAS, unità e via di esposizione sono obbligatori.")
|
|
else:
|
|
payload = {
|
|
"cas": cas,
|
|
"indicator": indicator,
|
|
"value": value,
|
|
"unit": unit,
|
|
"route": route,
|
|
"toxicity_type": toxicity_type or None,
|
|
"ref": ref or None,
|
|
}
|
|
try:
|
|
resp = add_tox_indicator(payload)
|
|
if resp.status_code == 200:
|
|
data = resp.json()
|
|
tox = data.get("data", {}).get("toxicity", {})
|
|
best = tox.get("best_case")
|
|
st.success(f"Indicatore aggiunto per CAS {cas}.")
|
|
if best:
|
|
st.info(f"Best case aggiornato: **{best['indicator']}** = {best['value']} {best['unit']} ({best['route']})")
|
|
elif resp.status_code == 404:
|
|
st.error(f"CAS {cas} non trovato in cache. Esegui prima una ricerca nella pagina Ingredienti.")
|
|
else:
|
|
st.error(f"Errore {resp.status_code}: {resp.json().get('detail', 'errore sconosciuto')}")
|
|
except Exception as e:
|
|
st.error(f"Errore: {e}")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# TAB 2 — Inventario Ingredienti
|
|
# ---------------------------------------------------------------------------
|
|
with tab_ingredienti:
|
|
st.subheader("Ingredienti nel database")
|
|
|
|
if st.button("Aggiorna", key="refresh_ingredienti"):
|
|
st.rerun()
|
|
|
|
try:
|
|
result = fetch_all_ingredients()
|
|
|
|
if result.get("success") and result.get("data"):
|
|
st.caption(f"{result['total']} ingredienti totali")
|
|
df = pd.DataFrame(result["data"])
|
|
df["dap"] = df["dap"].map({True: "OK", False: "-"})
|
|
df["cosing"] = df["cosing"].map({True: "OK", False: "-"})
|
|
df["tox"] = df["tox"].map({True: "OK", False: "-"})
|
|
df = df.rename(columns={
|
|
"cas": "CAS",
|
|
"dap": "DAP",
|
|
"cosing": "COSING",
|
|
"tox": "TOX",
|
|
"created_at": "Data Acquisizione",
|
|
})
|
|
st.dataframe(
|
|
df[["CAS", "DAP", "COSING", "TOX", "Data Acquisizione"]],
|
|
use_container_width=True,
|
|
hide_index=True,
|
|
)
|
|
else:
|
|
st.info("Nessun ingrediente trovato nel database.")
|
|
|
|
except Exception as e:
|
|
st.error(f"Errore nel caricamento: {e}")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# TAB 3 — Gestione Clienti
|
|
# ---------------------------------------------------------------------------
|
|
with tab_clienti:
|
|
st.subheader("Clienti registrati")
|
|
|
|
if st.button("Aggiorna", key="refresh_clienti"):
|
|
st.rerun()
|
|
|
|
clienti = fetch_clients()
|
|
|
|
if not clienti:
|
|
st.info("Nessun cliente trovato.")
|
|
else:
|
|
for cliente in clienti:
|
|
col_nome, col_id, col_btn = st.columns([4, 1, 1])
|
|
with col_nome:
|
|
st.write(cliente["nome_cliente"])
|
|
with col_id:
|
|
st.caption(f"id: {cliente['id_cliente']}")
|
|
with col_btn:
|
|
key = f"del_{cliente['id_cliente']}"
|
|
if st.button("Elimina", key=key, type="secondary"):
|
|
st.session_state[f"confirm_{cliente['id_cliente']}"] = True
|
|
|
|
if st.session_state.get(f"confirm_{cliente['id_cliente']}"):
|
|
nome = cliente["nome_cliente"]
|
|
st.warning(f"Confermi l'eliminazione di **{nome}**?")
|
|
col_si, col_no, _ = st.columns([1, 1, 6])
|
|
with col_si:
|
|
if st.button("Sì, elimina", key=f"yes_{cliente['id_cliente']}", type="primary"):
|
|
try:
|
|
r = delete_client(nome)
|
|
if r.status_code == 200:
|
|
st.success(f"Cliente '{nome}' eliminato.")
|
|
st.session_state.pop(f"confirm_{cliente['id_cliente']}", None)
|
|
st.rerun()
|
|
elif r.status_code == 409:
|
|
st.error(r.json().get("detail", "Il cliente ha ordini collegati."))
|
|
st.session_state.pop(f"confirm_{cliente['id_cliente']}", None)
|
|
else:
|
|
st.error(f"Errore {r.status_code}: {r.json().get('detail', '')}")
|
|
st.session_state.pop(f"confirm_{cliente['id_cliente']}", None)
|
|
except Exception as e:
|
|
st.error(f"Errore: {e}")
|
|
with col_no:
|
|
if st.button("Annulla", key=f"no_{cliente['id_cliente']}"):
|
|
st.session_state.pop(f"confirm_{cliente['id_cliente']}", None)
|
|
st.rerun()
|